RxSwift ch 18. Table & Collection views
이번 글은 RxSwift ch18을 공부하고 이를 기록하고자 함
목차
- BaseView 만들어보기
- modelSelected 사용법
- Mutiple Cell Types
BaseView 만들어보기
개발을 하다 보니 같은 UI도 여러개의 뷰에서 사용하는 경우가 있음
- 하지만 이전에는 이 방법을 몰라서 그냥 복사 붙여넣기로 사용했었는데, BaseView를 사용해보고자 함.
코드 샘플
import UIKit
import RxCocoa
import RxSwift
import SnapKit
import Then
struct BaseView {
var tableView = UITableView().then {
$0.backgroundColor = .blue
$0.rowHeight = 60
}
var multipleBtn = UIButton().then {
$0.setTitle("multipleBtn", for: .normal)
$0.backgroundColor = .green
}
func setBaseConstraints(view: UIView) {
tableView.snp.makeConstraints {
$0.edges.equalTo(view.safeAreaLayoutGuide)
}
multipleBtn.snp.makeConstraints {
$0.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide)
}
}
func setAddviews(view: UIView) {
[tableView, multipleBtn].forEach{ view.addSubview($0) }
}
}
사용예시
class BasicTableViewController: UIViewController {
let bv1 = BaseView()
var bag = DisposeBag()
var actioneBtn = UIButton().then {
$0.setTitle("actioneBtn", for: .normal)
$0.backgroundColor = .magenta
}
override func viewDidLoad() {
super.viewDidLoad()
bv1.setAddviews(view: view)
[actioneBtn].forEach { view.addSubview($0) }
bv1.setBaseConstraints(view: view)
actioneBtn.snp.makeConstraints {
$0.leading.trailing.equalToSuperview()
$0.bottom.equalTo(bv1.multipleBtn.snp.top)
}
bv1.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
bindTableView()
}
private func bindTableView() {
let cities = Observable.of(["Lisbon", "Copenhagen", "London", "Madrid", "Vienna"])
// MARK: Basic Table View
cities
.bind(to: bv1.tableView.rx.items) {
(tableView: UITableView, index: Int, element: String) in
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = element
return cell
}
.disposed(by: bag)
// modelSelected(_:)는 model object(cell에 의해 보여지는 것)을 emit 한다.
bv1.tableView.rx.modelSelected(String.self)
.bind { model in
print("\(model) was selected")
}
.disposed(by: bag)
// modelDeleted(_:)는 항목 삭제시 이벤트 발생 - tableView:commitEditingStyle:forRowAtIndexPath
bv1.tableView.rx.modelDeleted(String.self)
.bind { model in
print("\(model) was modelDeleted")
}
.disposed(by: bag)
// itemDeleted는 항목 삭제시 이벤트 발생
bv1.tableView.rx.itemDeleted
.bind { index in
print("\(index.row) was itemDeleted")
}
.disposed(by: bag)
// 악세서리버튼 탭하면 이벤트 발생
bv1.tableView.rx.itemAccessoryButtonTapped
.bind { index in
print("\(index.row) was itemAccessoryButtonTapped")
}
.disposed(by: bag)
bv1.multipleBtn.rx.tap
.bind { self.navigationToMultiple() }
.disposed(by: bag)
actioneBtn.rx.tap
.bind { self.navigationToAction() }
.disposed(by: bag)
}
}
extension UIViewController {
func navigationToMultiple() {
let vc = MultipleTableViewController()
// self.present(vc, animated: true, completion: nil)
navigationController?.pushViewController(vc, animated: true)
}
func navigationToAction() {
let vc = ActionViewController()
// self.present(vc, animated: true, completion: nil)
navigationController?.pushViewController(vc, animated: true)
}
}
Mutiple Cell Types
BaseView를 여러 셀에서 재사용.
import UIKit
import RxCocoa
import RxSwift
import SnapKit
import Then
class MultipleTableViewController: UIViewController {
let bv2 = BaseView()
var bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bv2.setAddviews(view: view)
bv2.setBaseConstraints(view: view)
bv2.tableView.register(TextCell.self, forCellReuseIdentifier: "titleCell")
bv2.tableView.register(ImageCell.self, forCellReuseIdentifier: "pairOfImageCell")
bv2.multipleBtn.isHidden = true
BindTableView()
}
private func BindTableView() {
let observable = Observable<[MyModel]>.just([
.text("Paris"),
.pairOfImgae(
UIImage(systemName: "plus")!,
UIImage(systemName: "minus")!
),
.text("Seoul"),
.pairOfImgae(
UIImage(systemName: "plus")!,
UIImage(systemName: "minus")!
)
])
observable.bind(to: bv2.tableView.rx.items) {
(tableView: UITableView, index: Int, element: MyModel) in
let indexPath = IndexPath(item: index, section: 0)
switch element {
case .text(let title):
let cell = self.bv2.tableView.dequeueReusableCell(withIdentifier: "titleCell", for: indexPath) as! TextCell
cell.titleLabel.text = title
return cell
case let .pairOfImgae(firstimage, secondimage):
let cell = self.bv2.tableView.dequeueReusableCell(withIdentifier: "pairOfImageCell", for: indexPath) as! ImageCell
cell.leftImage.image = firstimage
cell.rightImage.image = secondimage
return cell
}
}
.disposed(by: bag)
}
}
enum MyModel {
case text(String)
case pairOfImgae(UIImage, UIImage)
}
class TextCell: UITableViewCell {
var titleLabel = UILabel().then { _ in }
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .orange
[titleLabel].forEach {
contentView.addSubview($0)
}
setContstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setContstraints() {
titleLabel.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}
class ImageCell: UITableViewCell {
var leftImage = UIImageView().then { _ in }
var rightImage = UIImageView().then { _ in }
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
[leftImage, rightImage].forEach {
contentView.addSubview($0!)
}
setContstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setContstraints() {
leftImage.snp.makeConstraints {
$0.top.leading.bottom.equalToSuperview()
$0.trailing.equalTo(contentView.snp.centerX)
}
rightImage.snp.makeConstraints {
$0.top.trailing.bottom.equalToSuperview()
$0.leading.equalTo(contentView.snp.centerX)
}
}
}
'apple > RxSwift, ReactorKit' 카테고리의 다른 글
RxSwift Signal,Emit (0) | 2022.02.19 |
---|---|
iOS RxAction (RxSwift Community) (0) | 2022.01.19 |
Extension Reactive (RxSwift) (1) | 2022.01.12 |
iOS RxDelegateProxy 만들어보기 #1 (0) | 2022.01.12 |
iOS RxStarScream 총정리 (0) | 2022.01.12 |