RxDataSource 动画数据源
2017-06-23 本文已影响401人
anddygon
//
// 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
}
}