如何从Observable RxSwift 设置collectionView sizeForItemAt

问题描述 投票:0回答:1

在尝试使集合视图单元格的高度动态化时,我遇到了一些问题。高度数据位于我的枚举

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
进行访问,以便我可以访问我的身高

swift uikit rx-swift collectionview
1个回答
0
投票

我一直使用约束来设置单元格的高度。我建议您在单元格内容视图上添加高度约束,并将高度传递到单元格中,就像处理其他配置数据一样。

但是,如果您想继续使用

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(在委托代理内)

© www.soinside.com 2019 - 2024. All rights reserved.