在tvOS上运行时动态调整UITableViewCell的大小

时间:2018-07-09 14:42:07

标签: swift uitableview uiview uicollectionview tvos

我目前有一个UIViewController,具有以下层次结构:

UIViewController
-- UIView
---- UITableView
------ UITableViewCell
-------- UICollectionView
---------- UICollectionViewCell
-------- UIView
---------- UIStackView
------------ UILabel
------------ UILabel

所以基本上,我有一个UITableViewCell,包含一个UICollectionView和一个UIView,并在Interface Builder中定义了以下约束:

UICollectionView.leading = Superview.leading
UICollectionView.trailing = Superview.trailing
UICollectionView.top = Superview.top
UICollectionView.bottom = UIView.top
UIView.leading = Superview.leading
UIView.trailing = Superview.trailing
UIView.bottom = Superview.bottom

UICollectionView也使用水平流布局进行设置。

在ViewController中,我也为heightForRowAtIndexPath覆盖了UITableView数据源功能。

结果是UITableViewCell s的垂直滚动列表,每个UITableViewCell将具有UIImageView s的水平滚动列表。 UIView及其两个UILabel将在聚焦时向UIImageView显示相关信息。

我要实现的目标是,当焦点移到另一个UIView时隐藏包含两个UILabel的{​​{1}}。我可以通过覆盖UITableViewCell函数来捕获并检测焦点的变化。我可以减小didUpdateFocusInContext中先前集中的UITableViewCell的高度,但是先前集中的UICollectionViewDelegate和当前集中的UITableViewCell之间的差距保持不变。

尝试将UITableView.RowHeight设置为UITableViewAutomaticDimension,将UITableView.EstimatedRowHeight设置为任意数字,除去覆盖的heightForRowAtIndexPath函数,将导致UICollectionView不完全加载。

有人对我可以尝试的方法有很好的建议吗?

编辑:示例源代码

ViewController

// ==== ViewController.swift ====
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!

    let cellIdentifier = "\(CVTableViewCell.self)"

    override func viewDidLoad() {
        super.viewDidLoad()

        setupControls()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

        setupControls()
    }

    func setupControls() {
        setupTableView()
    }

    func setupTableView() {
        tableView.dataSource = self
        tableView.delegate = self

        // causes collectionView in CVTableViewCell to not load            
//        tableView.rowHeight = UITableViewAutomaticDimension
//        tableView.estimatedRowHeight = 200

        tableView.register(UINib(nibName: cellIdentifier, bundle: nil),
                           forCellReuseIdentifier: cellIdentifier)
    }
}

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 316.0 + 106.0 // 316.0 for image height, 106.0 for labelContainerView
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {    
        guard let dequeuedCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CVTableViewCell else {
            fatalError("Unable to dequeue cell")
        }

        return dequeuedCell
    }
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool {
        return false
    }
}

CVTableViewCell

// ==== CVTableViewCell.swift ====
import Foundation
import UIKit

class CVTableViewCell: UITableViewCell {
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var labelContainerView: UIView!
    @IBOutlet weak var labelContainerStackView: UIStackView!
    @IBOutlet weak var firstLabel: UILabel!
    @IBOutlet weak var secondLabel: UILabel!

    let cellIdentifier = "\(CVCollectionViewCell.self)"

    override func awakeFromNib() {
        super.awakeFromNib()

        setupControls()
    }

    override func prepareForReuse() {
        super.prepareForReuse()

        setupControls()
    }

    func setupControls() {
        setupTableViewCell()
        setupCollectionView()
        setupLabelContainerView()
        setupLabelContainerStackView()
        setupLabels()
    }

    func setupTableViewCell() {
        contentView.backgroundColor = .clear
    }

    func setupCollectionView() {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.itemSize = CGSize(width: 316.0, height: 316.0)
        layout.minimumInteritemSpacing = 0.0
        layout.minimumLineSpacing = 50.0

        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.backgroundColor = .clear
        collectionView.clipsToBounds = false
        collectionView.collectionViewLayout = layout
        collectionView.register(UINib(nibName: cellIdentifier, bundle: nil),
                                forCellWithReuseIdentifier: cellIdentifier)
    }

    func setupLabelContainerView() {
        labelContainerView.backgroundColor = .clear
    }

    func setupLabelContainerStackView() {
        labelContainerStackView.backgroundColor = .clear
        labelContainerStackView.distribution = .fillEqually
    }

    func setupLabels() {
        firstLabel.text = "Look at me"
        secondLabel.text = "I refuse to go away"
    }
}

extension CVTableViewCell: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let dequeuedCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? CVCollectionViewCell else {
            fatalError("Unable to dequeue cell")
        }

        dequeuedCell.imageView.adjustsImageWhenAncestorFocused = true
        dequeuedCell.imageView.image = #imageLiteral(resourceName: "stackoverflow")

        return dequeuedCell
    }
}

extension CVTableViewCell: UICollectionViewDelegate {
    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        super.didUpdateFocus(in: context, with: coordinator)

        // if next focused view is within current collectionview, show labelContainerView
        // else hide
        if let cell = context.nextFocusedView as? CVCollectionViewCell,
            let _ = collectionView.indexPath(for: cell) {
            labelContainerView.isHidden = false
        } else {
            labelContainerView.isHidden = true
        }
    }
}

CVCollectionViewCell

// ==== CVCollectionViewCell.swift ====
import Foundation
import UIKit

class CVCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var imageView: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()

        setupControls()
    }

    override func prepareForReuse() {
        super.prepareForReuse()

        setupControls()
    }

    func setupControls() {
        setupImageView()
    }

    func setupCollectionViewCell() {
        backgroundColor = .clear
    }

    func setupImageView() {
        imageView.image = nil
    }
}

0 个答案:

没有答案