Created
March 31, 2024 15:17
-
-
Save J0onYEong/07012d406518f2eaee7819b5a509d9de to your computer and use it in GitHub Desktop.
[RxSwift+MVVM] 특정 뷰에속할 경우 상태가 변경되는 UITableViewCell입니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
class NumberElementModel { | |
let id: Int | |
let number: Int | |
var isInside: Bool | |
init(id: Int, number: Int, isInside: Bool) { | |
self.id = id | |
self.number = number | |
self.isInside = isInside | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import RxSwift | |
import RxCocoa | |
class ViewController: UIViewController { | |
let viewModel = TableListViewModel() | |
let disposeBag = DisposeBag() | |
let tableView: UITableView = { | |
let tableView = UITableView() | |
tableView.translatesAutoresizingMaskIntoConstraints = false | |
tableView.rowHeight = 56 | |
tableView.register(TableViewCell.self, forCellReuseIdentifier: String(String(describing: TableViewCell.self))) | |
return tableView | |
}() | |
let detectArea: UIView = { | |
let view = UIView() | |
view.backgroundColor = .black.withAlphaComponent(0.1) | |
view.isUserInteractionEnabled = false | |
view.translatesAutoresizingMaskIntoConstraints = false | |
return view | |
}() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
tableView.delegate = self | |
setAutoLayout() | |
setObservable() | |
} | |
func setAutoLayout() { | |
view.addSubview(tableView) | |
view.insertSubview(detectArea, aboveSubview: tableView) | |
NSLayoutConstraint.activate([ | |
tableView.topAnchor.constraint(equalTo: view.topAnchor), | |
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), | |
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | |
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | |
detectArea.heightAnchor.constraint(equalToConstant: 100), | |
detectArea.centerYAnchor.constraint(equalTo: view.centerYAnchor), | |
detectArea.trailingAnchor.constraint(equalTo: view.trailingAnchor), | |
detectArea.leadingAnchor.constraint(equalTo: view.leadingAnchor), | |
]) | |
} | |
func setObservable() { | |
viewModel | |
.numberListObservable | |
.observe(on: MainScheduler.instance) | |
.bind(to: tableView.rx.items(cellIdentifier: String(describing: TableViewCell.self), cellType: TableViewCell.self)) { _, item, cell in | |
cell.numberLabelView.text = "\(item.number)번" | |
cell.stateLabelView.text = item.isInside ? "겹침" : "안겹침" | |
cell.backgroundColor = (item.isInside ? UIColor.blue : UIColor.red).withAlphaComponent(0.3) | |
cell.onStateChange = { [weak self] isInside in | |
self?.viewModel.changeState(isInside: isInside, id: item.id) | |
} | |
} | |
.disposed(by: disposeBag) | |
} | |
} | |
extension ViewController: UITableViewDelegate { | |
func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
guard let tableView = scrollView as? UITableView else { | |
return | |
} | |
tableView.visibleCells.forEach { cell in | |
guard let tableViewCell = cell as? TableViewCell else { return } | |
// tableView를 기준으로한 Cell의 프레임을 detectAreat뷰의 좌표계로부터의 프레임 | |
let frameFromDetactArea = tableView.convert(tableViewCell.frame, to: detectArea) | |
let isInside = (frameFromDetactArea.origin.y+frameFromDetactArea.height) >= 0 && frameFromDetactArea.origin.y <= detectArea.bounds.height | |
tableViewCell.onStateChange?(isInside) | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import RxSwift | |
import RxCocoa | |
class TableListViewModel { | |
let numberListObservable: BehaviorRelay<[NumberElementModel]> = BehaviorRelay(value: []) | |
init() { | |
numberListObservable | |
.accept(Array(1...100).map({ | |
NumberElementModel(id: $0, number: $0, isInside: false) | |
})) | |
} | |
func changeState(isInside: Bool, id: Int) { | |
_ = numberListObservable | |
.take(1) | |
.map { elements in | |
if let model = elements.first(where: { $0.id == id }) { | |
model.isInside = isInside | |
} | |
return elements | |
} | |
.subscribe(onNext: { | |
self.numberListObservable.accept($0) | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment