Как создать несколько разделов в UICollectionView с несколькими заголовками, используя RxDatasource - PullRequest
1 голос
/ 10 октября 2019

Прежде, чем кто-либо сделает его дубликатом, у меня есть сценарии всех тегов RxDatasource на SO и других сайтах. Но никто не работал на меня.

Так что мой вопрос полностью связан с этим вопросом, за которым я следовал и для своего случая. Но я также понятия не имею, что здесь происходит. И это были две недели борьбы. Я проверил пример кода gitHub, но не смог понять. Я создал приложение, используя RxSwift и Realm на MVVM шаблоне архитектуры, все работает хорошо, но теперь мне нужно создать два раздела в моем представлении, используя UICollectioView, для которых я прочитал о RxdataSource и пытался применить его, но я не понял, что он на самом деле делает. Я пытался создавать другие проекты для обучения, и те, которые тоже не работали. Тем не менее я пытался и сделать этот код, но он дает мне ошибку.

То, что я сделал, по приведенной выше ссылке в коде ниже. Я также не знаю, как дать моему источнику данных данные или списки из одного массива после его разделения. ниже весь мой код

Понятия не имею, что делает этот блок.

//Changed
struct SectionViewModel {
    var header: String!
    var items: [StudentModel]
}

extension SectionViewModel: SectionModelType {
    typealias Item  = StudentModel
    init(original: SectionViewModel, items: [StudentModel]) {
        self = original
        self.items = items
    }
}

тогда мой класс CollectionView будет выглядеть как

class StudentCV: UIViewController, UICollectionViewDelegateFlowLayout {

    //MARK: - Outlets

    @IBOutlet weak var studentsView: UICollectionView!

    let studentCells = BehaviorRelay<[StudentModel]>(value: [])
    var notificationToken: NotificationToken? = nil

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let flowLayout = UICollectionViewFlowLayout()
        let size = CGSize(width: 105, height: 135)
        flowLayout.itemSize = size
        studentsView.setCollectionViewLayout(flowLayout, animated: true)
        studentsView.rx.setDelegate(self).disposed(by: disposeBag)

        setupBinding()
    }

    func studentLeft(value: Int, id: Int) {
        SignalRService.sharedClass.chatHub.invoke(method: "StudentLeft", withArgs: [id, value]){ (result, error) in
            if let e = error {
                print("Error: \(e)")
            } else {
                print("Done!")
                let vale = Database.singleton.updatePickupStatus(studentId: id, pickupValue: value)
                TestDebug.debugInfo(fileName: "", message: "STUDENT LEFTTT:: \(vale)")
                if let r = result {
                    print("Result: \(r)")
                }
            }
        }
    }

    deinit {
        notificationToken?.invalidate()
    }
    func setupBinding() {
        studentsView.register(UINib(nibName: "StudentCVCell", bundle: nil), forCellWithReuseIdentifier: "studentCV")

        //Cell creation Changed here..............................

           dataSource.configureCell = { (ds, cv, ip, item) in
            let cell = cv.dequeueReusableCell(withReuseIdentifier: "studentCV", for: ip) as! StudentCVCell
            cell.viewModel = item
            return cell
        }


            studentCells
                .asObservable()
                .debug("STudent View: ")
                .map({ SectionViewModel(header: "Pickups Arrived", items: $0 ) })
                .bind(to: studentsView.rx.items(dataSource: dataSource)) // now here it is giving me this error (Instance method 'items(dataSource:)' requires the types '[SectionViewModel]' and 'SectionViewModel' be equivalent)
                .disposed(by: disposeBag)


        // item selection with model details.
        Observable
        .zip(
            studentsView
            .rx
            .itemSelected,
            studentsView
            .rx
            .modelSelected(StudentModel.self))
            .bind { [weak self] indexPath, model in

                let cell = self?.studentsView.cellForItem(at: indexPath) as? StudentCVCell
                if (model.pickupStatus == 2) {
                    // updating view accordingly
                }

        }.disposed(by: disposeBag)
    }

и ViewModels выглядит следующим образом. откуда я заполняю.

class StudentCollectionViewViewModel {


    //MARK: Outlets
    let disposeBag = DisposeBag()
    var notificationToken : NotificationToken? = nil
    let studentCells = BehaviorRelay<[StudentModel]>(value: [])

    var studentCell : Observable<[StudentModel]> {
        return studentCells.asObservable()
    }


    deinit {
        notificationToken?.invalidate()
    }

    func getStudentsData(id: Int) {

        let studentsData = Database.singleton.fetchStudents(byCLassId: id)
        self.notificationToken = studentsData.observe{[weak self] change in
            TestDebug.debugInfo(fileName: "", message: "Switch:::: change")
            switch change {
            case .initial(let initial):
                TestDebug.debugInfo(fileName: "", message: "INIT: \(initial)")
                self!.studentCells.accept(Array(studentsData))
            case .update(_, let deletions, let insertions, let modifications):
                TestDebug.debugInfo(fileName: "", message: "MODIF::: \(modifications)")
                self!.studentCells.accept(Array(studentsData))
            case .error(let error):
                print(error)
            }
        }


    }

}

Я заполняю данные из БД, но мне нужно сделать два списка, я также не получаю, куда мне нужно отправить два списка данных для заполнения. плюс, когда я пытался использовать его в своем коде, чтобы увидеть, как все работает, но это выдает мою следующую ошибку. Метод экземпляра 'items (dataSource :)' требует, чтобы типы '[SectionModel]' и '[StudentModel]' были эквивалентны . Любой совет или помощь будут оценены. заранее спасибо

1 Ответ

1 голос
/ 11 октября 2019

RxCollectionViewSectionedReloadDataSource<SectionModel> ожидает, что вы будете связывать элементы типа SectionModel, потому что вы передали SectionModel в качестве универсального параметра. Видимо, вы хотели бы использовать StudentModel. Чтобы достичь этого, вы можете заставить ваш StudentModel соответствовать SectionModelType протоколу, а затем использовать RxCollectionViewSectionedReloadDataSource<StudentModel>:

extension StudentModel: SectionModelType {
    // implement
}

let dataSource = RxCollectionViewSectionedReloadDataSource<StudentModel>(configureCell: { (datasource, collectionView, indexPath, element) in
    // configure a cell     
})
studentCells.bind(to: studentsView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag) // don't forget to setup disposal

Но я предполагаю, что StudentModel описывает одну ячейку, а невесь раздел. В таком случае, возможно, было бы лучше сопоставить StudentModel с SectionModel, например:

let dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel>(configureCell: { (datasource, collectionView, indexPath, element) in
    // configure a cell      
})
studentCells
    .map { [SectionModel(model: "", items: $0)] }
    .bind(to: studentsView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)

Очевидно, я отобразил все ваши studentCells в один раздел, который может бытьтвой случай. В более сложных сценариях вы можете рассмотреть возможность реализации пользовательского типа, соответствующего SectionModelType.

Также вы можете передать что-то более ценное, чем пустая строка, как model, но опять же, это зависит от ваших потребностей.

Внимание! В приведенном выше примере SectionModel означает RxDataSources.SectionModel, а не:

enum SectionModel {
    case SectionOne(items: [SectionItem])
    case SectionTwo(items: [SectionItem])
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...