apple/RxSwift, ReactorKit

RxSwift ch 18. Table & Collection views

lgvv 2022. 1. 18. 16:15

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)
        }
    }
}

 

(좌) BasicTableViewController (우) MultipleTableViewController

'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