본문 바로가기

iOS 개발/코로나검사소 앱(RxSwift)

코로나 검사소 - 3. 코로나 센터 선택 화면

반응형

안녕하세요. Skillist입니다

 

이번엔 코로나 센터 화면을 구현하겠습니다.

 

———————————————————————————————————————————————————

 

먼저 ViewModel을 구현해볼게요.

 

기능이 간단해서, viewModel도 간단합니다.

viewModel에서 view로 전달하는건 2개밖에 없습니다.

코로나검사소 어레이인 "[Center]"와 Center에서 가져온 String타입의 지역 이름 입니다.

 

20라인 : 이니셜라이저에서 Center어레이를 넘겨받고, 이를 Driver로 전달합니다.

 

24라인 : center에서 지역 이름을 받아와서 driver로 전달합니다.

 

그리고 cellData와 navigationTitle을 view에서 바인드하죠.

 

———————————————————————————————————————————————————

 

그럼 view를 볼게요.

레이아웃 먼저 보고, 이후에 bind를 볼게요.

 

15라인 : 화면에는 테이블 뷰만 추가할겁니다. 좋죠??? 테이블뷰입니다.

 

67라인 : 뷰 설정이 없어서, 따로 구현하진 않았어요.

 

71라인 : 테이블뷰를 추가하고 snapKit으로 제약사항을 구성했습니다.

 

그럼 이번엔 바인드를 볼게요.

34라인 : tableview에 viewModel.cellData를 바인드합니다. 드라이브한다고 해야하나요?

 

44라인 : viewModel.nagivationTitle을 네비게이션 타이틀에 드라이브합니다.

그래서, 타이틀을 구현했기때문에, 67라인에서 구현코드가 없는겁니다.

 

52라인 : 주석으로도 써놨지만, 지역선택 화면 구현 코드와는 다르게, 이번엔 Observable.zip을 활용하여,

tableView.rx.itemSelected와 tableView.rx.modelSelected를 묶었어요.

결과적으로 indexPath와 data를 모두 전달받을 수 있습니다.

참고로, zip의 순서를 변경하면, indexPath와 data의 순서도 변경됩니다.

아! indexPath를 받은 이유는, cell을 선택하면 select된 상태(클릭된 상태)가 됩니다. 이를 deselect하기 위해서, indexPath를 받았어요.

이는 개발에 잘사용하기 때문에, 익혀두시면 좋을거에요. 네! 알겠습니다.

 

———————————————————————————————————————————————————

 

이번엔 테이블뷰에서 사용할 코로나 센터 cell을 볼게요

 

2개의 스택뷰를 사용했어요.

SwiftUI도 살짝 공부했는데, 1월 동안 

SwiftUI와 같이 VStackView, HStackView으로 명명해봤어요.

 

13라인 : titleLabel입니다.

 

20라인 : typeLabel입니다.

 

27라인 : stackView로 구현합니다.

그럼 다음과 같이 구현되죠.

 

42라인 : addressLabel입니다.

 

49라인 : phoneLabel입니다.

 

56라인 : stackView입니다. 구현하면 다음과 같이 됩니다.

 

73라인 : 이니셜라이저에서, cell 레이아웃을 구성했어요.

 

87라인 : 데이터를 설정합니다.

 

91라인 : 전화번호가 드러나서, 임의 번호로 입력했습니다. 신경쓰지 마세요.

 

———————————————————————————————————————————————————

 

이번 프로젝트의 포커스는 RxSwift이기 때문에,

저와 같이 자주 구현해본 레이아웃과 SnapKit은 빠르게 지나갔습니다.

RxSwift 코드도 적어서 빠르게 지나갔네요;;;;;;; 

다음 프로젝트엔 좀더 RxSwift를 활용하는 프로젝트로 구현해볼게요.

아! 아직 안끝났습니다.

 

잘못되거나 부족한 내용 등, 피드백 감사합니다!

 

https://github.com/DeveloperSkillist/CoronaCenterRxSwift

 

GitHub - DeveloperSkillist/CoronaCenterRxSwift

Contribute to DeveloperSkillist/CoronaCenterRxSwift development by creating an account on GitHub.

github.com

 

 

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  전체 코드  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

import Foundation
import RxSwift
import RxCocoa

struct SelectCenterViewModel {
    
    //view -> viewModel
    
    //viewModel -> view
    var cellData : Driver<[Center]>
    var navigationTitle: Driver<String>
    
    init(centers: [Center]) {
        cellData = Observable.just(centers)
            .asDriver(onErrorDriveWith: .empty())
            
        navigationTitle = Observable.just(centers.first?.sido.rawValue ?? "-")
            .asDriver(onErrorJustReturn: "-")
    }
}
import Foundation
import RxSwift
import RxCocoa

class SelectCenterView: UIViewController {
    var disposeBag = DisposeBag()
    
    private lazy var tableView: UITableView = {
        var tableView = UITableView()
        tableView.register(SelectCenterViewCell.self, forCellReuseIdentifier: "SelectCenterViewCell")
        return tableView
    }()
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        
        attribute()
        layout()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func bind(_ viewModel: SelectCenterViewModel) {
        viewModel.cellData
            .drive(tableView.rx.items) { tv, row, data in
                guard let cell = tv.dequeueReusableCell(withIdentifier: "SelectCenterViewCell") as? SelectCenterViewCell else {
                    return UITableViewCell()
                }
                cell.setData(center: data)
                return cell
            }
            .disposed(by: disposeBag)
        
        viewModel.navigationTitle
            .drive {
                self.navigationItem.title = $0
            }
            .disposed(by: disposeBag)
        
        Observable.zip(
            tableView.rx.itemSelected,
            tableView.rx.modelSelected(Center.self)
        )
            .bind { [weak self] indexPath, data in
                self?.tableView.deselectRow(at: indexPath, animated: true)
                
                let detailMapViewModel = DetailMapViewModel(center: data)
                let detailMapView = DetailMapView()
                detailMapView.bind(detailMapViewModel)
                self?.navigationController?.pushViewController(detailMapView, animated: true)
            }
            .disposed(by: disposeBag)
    }
    
    private func attribute() {
        
    }
    
    private func layout() {
        view.addSubview(tableView)
        
        tableView.snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
    }
}
import Foundation
import UIKit

class SelectCenterViewCell: UITableViewCell {
    
    private lazy var titleLabel: UILabel = {
        var label = UILabel()
        label.font = .boldSystemFont(ofSize: 15)
        label.textColor = .black
        return label
    }()
    
    private lazy var typeLabel: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 15)
        label.textColor = .gray
        return label
    }()
    
    private lazy var titleStackView: UIStackView = {
        var HStackView = UIStackView()
        HStackView.axis = .horizontal
        HStackView.spacing = 5
        
        [
            titleLabel,
            typeLabel
        ].forEach {
            HStackView.addArrangedSubview($0)
        }
        
        return HStackView
    }()
    
    private lazy var addressLabel: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 15)
        label.textColor = .black
        return label
    }()
    
    private lazy var phoneLabel: UILabel = {
        var label = UILabel()
        label.font = .systemFont(ofSize: 15)
        label.textColor = .link
        return label
    }()
    
    private lazy var labelStackView: UIStackView = {
        var VStackView = UIStackView()
        VStackView.axis = .vertical
        VStackView.distribution = .equalSpacing
        VStackView.spacing = 5
        
        [
            titleStackView,
            addressLabel,
            phoneLabel
        ].forEach {
            VStackView.addArrangedSubview($0)
        }
        
        return VStackView
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        addSubview(labelStackView)
        
        labelStackView.snp.makeConstraints {
            $0.edges.equalToSuperview().inset(15)
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setData(center: Center) {
        titleLabel.text = center.facilityName
        typeLabel.text = center.centerType.rawValue
        addressLabel.text = center.address
        phoneLabel.text = "000-000-0000"
    }
    
}

 

반응형