我目前有一个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
}
}