質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1682閲覧

tableViewをスクロールした際、SectionHeaderViewのUIlabelが横からフェードインする。

atk_721

総合スコア62

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/09/07 08:59

編集2020/09/08 01:00

前提・実現したいこと

sectionHeaderのUIlabelがスクロール時にフェードインするのを防ぎたいです。
スクロールの速さに関わらず横からフェードインします。
横からフェードインするSectionはバラバラです。画像では栃木が横からフェードインしていますが、しない時もあり、どういった法則で横からフェードインするSectionHeaderが決まっているのか理解できていません。

titleForHeaderInSection(tableViewDelegate)でSectionのtitleを渡した場合は、正常に動きました。
回答のほどよろしくお願いします。

##MainController

import UIKit import Firebase public let Prefectures = [ "北海道", "青森", "秋田",//割愛 ] public let tableCell = "MainTableCell" public let collectionCell = "CollectionCell" private let sectionReuseIdentifier = "SectionHeader" class MainController: UIViewController { //MARK: - Properties private var scrollUpDirection: Bool = false private let collectionSectionInSets: UIEdgeInsets = .init(top: 0, left: 10, bottom: 0, right: 10) private var prevcontentOffSet: CGPoint = .init(x: 0, y: 0) private let headerAnimationSpeed: CGFloat = 12 private let headerHeight: CGFloat = 120 private var headerViewHeightConstraint: NSLayoutConstraint! private lazy var screenSize = self.view.bounds private let tableView = UITableView(frame: .zero, style: .plain) private let headerView:MainHeaderView = { let view = MainHeaderView() view.backgroundColor = .systemPurple return view }() //MARK: - View LifeCycle override func viewDidLoad() { super.viewDidLoad() checkFormStates() } override var prefersStatusBarHidden: Bool { return scrollUpDirection } override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { return .slide } //MARK: - Helpers func configureUI() { configureHeaderView() configureTableView() } fileprivate func configureHeaderView() { view.addSubview(headerView) headerView.anchor(top: view.topAnchor, left: view.leftAnchor, right: view.rightAnchor, width: screenSize.width) headerViewHeightConstraint = headerView.heightAnchor.constraint(equalToConstant: headerHeight) headerViewHeightConstraint.priority = UILayoutPriority(600) headerViewHeightConstraint.isActive = true } fileprivate func configureTableView() { tableView.delegate = self tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: tableCell) tableView.rowHeight = 200 tableView.tableFooterView = UIView() tableView.register(MainTableCell.self, forCellReuseIdentifier: tableCell) tableView.register(SectionHeaderView.self, forHeaderFooterViewReuseIdentifier: sectionReuseIdentifier) tableView.contentInsetAdjustmentBehavior = .never view.addSubview(tableView) tableView.anchor(top: headerView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, bottom: view.bottomAnchor) } func checkFormStates() { if Auth.auth().currentUser?.uid != nil && Auth.auth().currentUser?.isEmailVerified == true{ configureUI() }else{ DispatchQueue.main.async { let controller = SignInController() controller.modalPresentationStyle = .fullScreen self.present(controller, animated: true, completion: nil) } } } fileprivate func animationStatusBar() { UIView.animate(withDuration: 0.3) { self.setNeedsStatusBarAppearanceUpdate() } } } //MARK: - UITableView Datasource delegate extension MainController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { tableView.dequeueReusableHeaderFooterView(withIdentifier: sectionReuseIdentifier) let sectionHeader = SectionHeaderView(reuseIdentifier: sectionReuseIdentifier) sectionHeader.prefecturesName = Prefectures[section] return sectionHeader } func numberOfSections(in tableView: UITableView) -> Int { return Prefectures.count } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let cell = cell as? MainTableCell else { return } cell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: indexPath.section) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: tableCell, for: indexPath) return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } } //MARK: CollectionView Delegate DataSource extension MainController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 10 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCell, for: indexPath) as! MainCollectionCell return cell } } //MARK: - CollectionView Flowlayout extension MainController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 200, height: 180) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return collectionSectionInSets } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return collectionSectionInSets.left } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return collectionSectionInSets.left } }

##SectionHeaderView

import UIKit class SectionHeaderView: UITableViewHeaderFooterView { //MARK: - Properties internal var prefecturesName: String? { didSet { guard let prefecturesName = prefecturesName else { return } titleLabel.text = prefecturesName } } private lazy var titleLabel: UILabel = { let label = UILabel() label.font = UIFont.boldSystemFont(ofSize: 24) label.textAlignment = .center label.textColor = .black return label }() private let showButton: UIButton = { let button = UIButton(type: .system) button.setTitle("全て見る", for: .normal) button.titleLabel?.textColor = .systemBlue return button }() //MARK: - View LifeCycle override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) setHeight(height: 60) } override func layoutSubviews() { let view = UIView() view.frame = self.frame view.backgroundColor = .white backgroundView = view self.addSubview(titleLabel) titleLabel.centerY(inView: self) titleLabel.anchor(left: leftAnchor, padddingLeft: 16) addSubview(showButton) showButton.centerY(inView: self) showButton.anchor(right: rightAnchor, paddingRight: -16) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

##起動時の画面
イメージ説明
##スクロール時
イメージ説明
イメージ説明

補足情報(FW/ツールのバージョンなど)

swift5 xcode 11.6

##追記
1000文字を超えてしまうので不要なコードを添削しました。
sectionHeaderViewを登録して使いまわす様に変更しました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2020/09/07 11:39

正確にお答えできる回答はまだ持ち合わせていませんが、いただいたコードを使って追試した感じ、おそらく HeaderView の制約計算が間に合っていない感じがします。 たとえば、HeaderView のうち、ラベルの中心座標を View の中心座標と一致させて表示させると、フェードするようなことはなくなります。 あるいは、HeaderView についても、Cell と同じく register で登録し、dequeueReusableHeaderFooterView で使い回すようにすれば、オートレイアウトを使っても計算が間に合うようになるかもしれません(同じような現象が出る話は、ある本を読んで記載されていたのを思い出しました)。
atk_721

2020/09/08 00:51

ご指摘の通りdequeReusableHeaderForFooterViewを用いて実装しましたが、解決には至りませんでした。。。HeaderViewについてregisterで登録できることを知れたのでよかったです!回答ありがとうございました!!!
guest

回答1

0

ベストアンサー

たとえば、元の実装であればこんな感じにすると「フェードイン」することはなくなるかと思います(各種extensionは想像で作っているので、もしかしたら細かい点で解決していない部分はあるかもしれません)。

Swift

1import UIKit 2 3class SectionHeaderView: UIView { 4 // 略 5 init(prefeturesName: String, width w: CGFloat = 414) { 6 print(#function) 7 self.prefecturesName = prefeturesName 8 9 super.init(frame: CGRect(x: 0, y: 0, width: w, height: 40)) 10 titleLabel.sizeToFit() 11 titleLabel.center = center 12 self.addSubview(titleLabel) 13 } 14 15 deinit { 16 print("deinit", #function) 17 } 18 // 後略 19}

ここでは UIView の幅は 414 と決め打ちしていますが、ヘッダを作る際に適切に幅を指定すれば、他の機種にも適用できるかと思います。

Swift

1func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 2 let width = tableView.frame.width 3 let header = SectionHeaderView(prefeturesName: Prefectures[section], width: width) 4 5 return header 6 }

deinit {}で確認したところ、ヘッダが表示範囲から消えた段階で実行されているので、使われていないインスタンスが残ってしまうということはなさそうですが、パフォーマンスは悪いかもしれません。

シミュレータで試した感じですが、

同じようなヘッダをたくさん使うようであれば、Cell でやっているように使い回した方が明らかに効率が良いと思います。ただ、dequeueする時に contentView の幅を適切に計算する方法がいま思いつかないので(他の方だと簡単に記述できるかもしれません)、やはり場合によってはフェードインするときがあります。

ちなみに、registerし、dequeue するのであれば、

Swift

1 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 2 3 tableView.dequeueReusableHeaderFooterView(withIdentifier: sectionReuseIdentifier) 4 let sectionHeader = SectionHeaderView(reuseIdentifier: sectionReuseIdentifier) 5 sectionHeader.prefecturesName = Prefectures[section] 6 return sectionHeader 7 }

ではなく、

Swift

1 fileprivate func configureTableView() { 2 // 略 3 4 tableView.register(SectionHeaderView2.self, forHeaderFooterViewReuseIdentifier: "Header") 5 // 後略 6 }

といった感じで登録し(Cellのやり方と同じです)、

Swift

1 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 2 guard let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as? SectionHeaderView2 else { 3 return nil 4 } 5 6 header.prefLabel.text = Prefectures[section] 7 8 return header 9 }

といった感じで使うやり方になるかと思います(使い方もCellと同じです)。

投稿2020/09/08 02:19

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

atk_721

2020/09/08 06:06

何度も回答していただきありがとうございます!指摘の通りheaderの登録を変更し、クラスsectionHeader内でset Heightで高さの制約を持たせていたのを、消す事でフェードインしなくなりました!解決に導いて貰い感謝します!ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問