美文网首页
RxDataSource 动画数据源

RxDataSource 动画数据源

作者: anddygon | 来源:发表于2017-06-23 17:16 被阅读401次
    //
    //  ViewController.swift
    //  RxSwiftTest
    //
    //  Created by xiaoP on 2017/3/15.
    //  Copyright © 2017年 Chicv. All rights reserved.
    //
    
    import UIKit
    import RxSwift
    import RxCocoa
    import SnapKit
    import RxGesture
    import RxOptional
    import RxDataSources
    
    class ViewController: UIViewController {
    
        let tableView = UITableView(frame: CGRect.zero)
        let dataSource = RxTableViewSectionedAnimatedDataSource<PriceSectionModel>()
        let bag = DisposeBag()
        fileprivate var heightConstraint: Constraint?
        
        
        override func viewDidLoad() {
            super.viewDidLoad()
            configUI()
            bind()
        }
        
        fileprivate func configUI() {
            automaticallyAdjustsScrollViewInsets = false
            
            let rightItem = UIBarButtonItem(title: "insert/delete", style: .done, target: nil, action: nil)
            navigationItem.rightBarButtonItem = rightItem
            
            view.backgroundColor = UIColor.black
            view.addSubview(tableView)
            
            tableView.snp.makeConstraints { (make: ConstraintMaker) in
                make.left.right.bottom.equalToSuperview()
                self.heightConstraint = make.height.equalTo(0).constraint
            }
            tableView.delegate = self
            tableView.tableFooterView = UIView()
            tableView.register(UINib(nibName: "PriceCell", bundle: nil), forCellReuseIdentifier: "PriceCell")
            tableView.register(UINib(nibName: "PayCell", bundle: nil), forCellReuseIdentifier: "PayCell")
            
            dataSource.configureCell = { (ds, tv, ip, item) in
                switch item {
                case let .price(title, value):
                    let cell = tv.dequeueReusableCell(withIdentifier: "PriceCell", for: ip) as! PriceCell
                    cell.fillData(title: title, value: value)
                    return cell
                case .pay:
                    let cell = tv.dequeueReusableCell(withIdentifier: "PayCell", for: ip) as! PayCell
                    return cell
                }
            }
        }
        
        fileprivate func bind() {
            let items: Variable<[PriceItem]> = Variable([
                .price(title: "Sub Total", value: "$135.50"),
                .price(title: "Quantity", value: "6"),
                .price(title: "Standard Delivery", value: "$10.00"),
                .price(title: "Total", value: "$145.50"),
                .pay
            ])
            
            let rightItem = navigationItem.rightBarButtonItem!
            rightItem.rx.tap
                .map{ _-> PriceItem in
                    let count = Int(arc4random() % 1000)
                    return .price(title: "Inserted\(count)", value: "$0.00")
                }
                .bindNext { (item: PriceItem) in
                    let index = Int(arc4random() % UInt32(items.value.count))
                    if index % 2 == 0 && items.value.isNotEmpty {
                        items.value.remove(at: index)
                    } else {
                        items.value.insert(item, at: index)
                    }
                }
                .disposed(by: bag)
            
            let data = items
                .asObservable()
                .map { (items: [PriceItem]) -> [PriceSectionModel] in
                    return [PriceSectionModel(header: "", prices: items)]
                }
                
            data
                .delay(1.5, scheduler: MainScheduler.instance)
                .bindTo(tableView.rx.items(dataSource: dataSource))
                .disposed(by: bag)
            
            data
                .map { (sections: [PriceSectionModel]) -> CGFloat in
                    return sections.reduce(0){ (sum, section) in
                        return sum + section.items.reduce(0){ (sum, item) in
                            switch item {
                            case .price:
                                return sum + 44
                            case .pay:
                                return sum + 50
                            }
                        }
                    }
                }
                .bindNext { [weak self] (height: CGFloat) in
                    self?.heightConstraint?.update(offset: height)
                    UIView.animate(withDuration: 1, animations: { [weak self] in
                        self?.view.layoutIfNeeded()
                    })
                }
                .disposed(by: bag)
        }
        
    }
    
    extension ViewController: UITableViewDelegate {
        
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            let item = dataSource[indexPath]
            switch item {
            case .price:
                return 44
            case .pay:
                return 50
            }
        }
        
    }
    
    struct PriceSectionModel {
        var header: String
        var prices: [PriceItem]
        
        init(header: String, prices: [Item]) {
            self.header = header
            self.prices = prices
        }
        
    }
    
    extension PriceSectionModel: AnimatableSectionModelType {
        typealias Item = PriceItem
        typealias Identity = String
        
        var identity: String {
            return header
        }
        
        var items: [Item] {
            return prices
        }
        
        init(original: PriceSectionModel, items: [Item]) {
            self = original
            self.prices = items
        }
    }
    
    enum PriceItem: IdentifiableType, Equatable {
        typealias Identity = String
        
        case price(title: String, value: String)
        case pay
        
        var identity: String {
            switch self {
            case let .price(title, _):
                return "price-\(title)"
            case .pay:
                return "pay"
            }
        }
        
        static func ==(l: PriceItem, r: PriceItem)-> Bool {
            return l.identity == r.identity
        }
        
    }
    

    相关文章

      网友评论

          本文标题:RxDataSource 动画数据源

          本文链接:https://www.haomeiwen.com/subject/bzwccxtx.html