在尝试使集合视图单元格的高度动态化时,我遇到了一些问题。高度数据位于我的枚举
Observable<[MovieSection]>
数组内。据我所知,RxSwift 不提供 sizeForItemAt
委托函数。
那么,如何将
Observable<[MovieSection]>
数组传递给“sizeForItemAt”委托,以便我可以根据其大小写切换枚举并检索高度?
enum MovieSection {
case header(height: Double, movie: Movie)
case horizontal(title: String, height: Double, items: [Movie])
}
class ViewModel {
private var _sections = BehaviorRelay<[MovieSection]>(value: [])
var sections: Observable<[MovieSection]>? {
return _sections.asObservable()
}
func getData() {
//items and movie from somewhere i get from network/mock
let sectionsData: [MovieSection] = [
.header(height: 270, movie: popular[1]),
.horizontal(title: "Popular", height: 230, items: popular),
.horizontal(title: "Top Rated", height: 230, items: topRated)
]
_sections.accept(sectionsData)
}
}
class HomeViewController: UIViewController {
var viewModel = ViewModel()
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
setupBindings()
viewModel.getData()
}
private func setupBindings() {
viewModel.sections
.bind(to: collectionView.rx.items) { collectionView, row, item in
let indexPath = IndexPath(row: row, section: 0)
switch item {
case .header(_, let movie):
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HeaderSectionCell.identifier, for: indexPath) as! HeaderSectionCell
cell.configure(with: movie.backdropPath)
return cell
case .horizontal(let title, _, let movies):
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HorizontalMoviesCell.identifier, for: indexPath) as! HorizontalMoviesCell
cell.configure(with: title, items: movies)
return cell
}
}
.disposed(by: bag)
collectionView.rx.setDelegate(self)
.disposed(by: bag)
}
}
//MARK: UICollectionView Delegate
extension HomeViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//Here i want pass my height from my [MovieSection] array of enum so i can access my height
return CGSize(width: collectionView.frame.width, height: 230)
}
}
我之前所做的是直接访问BehaviorRelay中的值,因此我可以直接访问数组而不返回新的Observable变量
像这样:
func getSectionsValue() -> [MovieSection] {
return _sections.value
}
我希望从
Observable<[MovieSection]>
CollectionView 中的 sizeForItemAt
进行访问,以便我可以访问我的身高
我一直使用约束来设置单元格的高度。我建议您在单元格内容视图上添加高度约束,并将高度传递到单元格中,就像处理其他配置数据一样。
但是,如果您想继续使用
collectionView(_:layout:sizeForItemAt:)
,则需要BehaviorRelay。
最简单的方法是向视图控制器添加一个并将其绑定到
sections
可观察...
let heightForItemAt = BehaviorRelay<[CGFloat]>(value: [])
func setupBindings() {
viewModel.sections
.map { $0.map { $0.height } }
.bind(to: heightForItemAt)
.disposed(by: bag)
// the rest of the method as you have it...
}
以上假设您有这个:
extension MovieSection {
var height: Double {
switch self {
case .header(let height, _), .horizontal(_, let height, _):
return height
}
}
}
现在在您的委托方法中,您可以访问
heightForItemAt
继电器的值来获取高度。
如果您愿意,可以关注我的文章将 Swift Delegate 转换为 RxSwift Observables。然后你可以这样做:
viewModel.sections
.map { [collectionView] sections in
sections.map { CGSize(width: collectionView!.frame.width, height: $0.height) }
}
.bind(to: collectionView.rx.sizeForItemAt)
.disposed(by: bag)
但它仍然需要一个BehaviorSubject(在委托代理内)