Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- TableView
- Carousel CollectionView
- 양궁대회
- UIKit
- coremotion
- Input Output
- @escaping
- Value Type Reference Type
- SWIFT
- CoreData
- 면접을 위한 CS 전공 지식 노트 Tree
- NavigationSearchBar
- wil
- 테이블뷰 나누기
- 프로그래머스
- TableView Section
- tableview section별 다른 cell적용
- ReferceCycle
- Array vs Linked List
- 면접을 위한 CS전공 지식 노트
- retain cycle
- CarouselCollectionview
- UserDefaults
- 롤케이크 자르기
- Reference Cycle
- class struct
- 자료구조
- til
- 강한 참조 순환
- firebase
Archives
- Today
- Total
개발하는 동글 :]
[TIL],[UIKit],[Controller 상속해서 사용하기] 본문
1. 문제 상황
위의 이미지처럼 다양한 다양한 화면에서 비슷한 화면이 자주 사용된다. 그렇기에 반복되는 작업을 줄이고자 하였다.
2. 시도한 방법
2.1 LockScreenView 구현
더보기
//
// LockScreenView.swift
// FinalTodo
//
// Created by SeoJunYoung on 10/23/23.
//
import UIKit
class LockScreenView: UIView {
let titleLabel: UILabel = {
let label = UILabel()
label.font = .preferredFont(forTextStyle: .title1)
return label
}()
lazy var passwordCollectionView: UICollectionView = {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.itemSize = .init(width: Constant.screenWidth * 0.05, height: Constant.screenWidth * 0.05)
flowLayout.minimumLineSpacing = Constant.defaultPadding
flowLayout.scrollDirection = .horizontal
let view = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
view.backgroundColor = .clear
return view
}()
lazy var passwordInfoLabel: UILabel = {
let label = UILabel()
label.font = .preferredFont(forTextStyle: .body)
label.textColor = .red
label.textAlignment = .center
label.alpha = 0
return label
}()
lazy var numsCollectionView: UICollectionView = {
let flowLayout = UICollectionViewFlowLayout()
let spacing = Constant.defaultPadding
flowLayout.minimumLineSpacing = spacing
let width = (Constant.screenWidth - (Constant.defaultPadding * 6) - (spacing * 4)) / 3
flowLayout.itemSize = .init(width: width, height: width)
let view = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
view.backgroundColor = .clear
return view
}()
init() {
super.init(frame: CGRect.zero)
setUp()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
private extension LockScreenView {
// MARK: - SetUp
func setUp() {
setUpPasswordLabel()
setUpPasswordCollectionView()
setUpPasswordInfoLabel()
setUpNumsCollectionView()
}
func setUpPasswordLabel() {
self.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(Constant.screenHeight * 0.15)
make.centerX.equalToSuperview()
}
}
func setUpPasswordInfoLabel() {
self.addSubview(passwordInfoLabel)
passwordInfoLabel.snp.makeConstraints { make in
make.top.equalTo(passwordCollectionView.snp.bottom).offset(Constant.defaultPadding)
make.left.right.equalToSuperview().inset(Constant.defaultPadding)
}
}
func setUpPasswordCollectionView() {
self.addSubview(passwordCollectionView)
passwordCollectionView.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(Constant.defaultPadding)
make.left.right.equalToSuperview()
make.height.equalTo(Constant.screenWidth * 0.05)
}
passwordCollectionView.register(
LockScreenPasswordCollectionViewCell.self, forCellWithReuseIdentifier: LockScreenPasswordCollectionViewCell.identifier
)
}
func setUpNumsCollectionView() {
self.addSubview(numsCollectionView)
numsCollectionView.snp.makeConstraints { make in
make.top.equalTo(passwordCollectionView.snp.bottom).offset(Constant.screenHeight * 0.1)
make.left.right.equalToSuperview().inset(Constant.defaultPadding * 3)
make.bottom.equalToSuperview()
}
numsCollectionView.register(
LockScreenNumCollectionViewCell.self, forCellWithReuseIdentifier: LockScreenNumCollectionViewCell.identifier
)
}
}
view에 관한 부분을 분리하여 재사용하는 방법을 선택하였다. 그런데 이 방법 또 한 공통적으로 작동하는 로직들을 반복해서 적어야 한다는 문제점이 있어 반복되는 로직들 또 한 재사용하는 방법을 생각하던 중 상속하여 사용하는 방법을 시도하였다.
2.2 LockController 구현
더보기
//
// LockController.swift
// FinalTodo
//
// Created by SeoJunYoung on 10/23/23.
//
import Foundation
import UIKit
class LockController: UIViewController {
enum PasswordShowType {
case mismatch
case different
}
let lockScreenView = LockScreenView()
let userDefaultsManager = UserDefaultsManager()
lazy var lockScreenPassword = userDefaultsManager.getPassword()
let failCount: Observable<Int> = Observable(0)
let userInPutPassword: Observable<String> = Observable("")
let passwordCollectionviewSpacing = Constant.defaultPadding
let passwordCollectionviewItemSize: CGSize = .init(
width: Constant.screenWidth * 0.05,
height: Constant.screenWidth * 0.05
)
let passwordLength:CGFloat = 4
let numPadComposition = [
"1", "2", "3",
"4", "5", "6",
"7", "8", "9",
"AC","0", "C"
]
let numPadCollectionviewSpacing = Constant.defaultPadding * 2
lazy var numPadCollectionviewItemSize: CGSize = .init(
width: (Constant.screenWidth - (Constant.defaultPadding * 6) - (numPadCollectionviewSpacing * 2)) / 3,
height: (Constant.screenWidth - (Constant.defaultPadding * 6) - (numPadCollectionviewSpacing * 2)) / 3
)
deinit {
print("[LockScreenViewController]: deinit")
}
}
extension LockController {
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
setUp()
bind()
}
}
extension LockController {
// MARK: - Bind
@objc func bind() {
userInPutPassword.bind { [weak self] inputData in
guard let self = self else { return }
lockScreenView.passwordInfoLabel.alpha = 0
lockScreenView.passwordCollectionView.reloadData()
}
}
// MARK: - SetUp
func setUp() {
view.backgroundColor = ColorManager.themeArray[0].backgroundColor
view.addSubview(lockScreenView)
lockScreenView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
lockScreenView.numsCollectionView.delegate = self
lockScreenView.numsCollectionView.dataSource = self
lockScreenView.passwordCollectionView.delegate = self
lockScreenView.passwordCollectionView.dataSource = self
}
// MARK: - Method
func showPasswordMissMatch(type:PasswordShowType) {
userInPutPassword.value = ""
failCount.value += 1
print("FailCount:",failCount.value)
switch type {
case .different:
lockScreenView.passwordInfoLabel.text = "비밀번호가 일치하지 않습니다"
case .mismatch:
lockScreenView.passwordInfoLabel.text = "비밀번호를 확인해 주세요"
}
UIView.animate(withDuration: 1) {
self.lockScreenView.passwordInfoLabel.alpha = 1
}
lockScreenView.passwordCollectionView.shake()
}
}
extension LockController: UICollectionViewDelegate, UICollectionViewDataSource {
// MARK: - extension UICollectionViewDelegate, UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == lockScreenView.passwordCollectionView {
return Int(passwordLength)
} else {
return numPadComposition.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == lockScreenView.passwordCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LockScreenPasswordCollectionViewCell.identifier, for: indexPath) as! LockScreenPasswordCollectionViewCell
if indexPath.row < userInPutPassword.value.count {
cell.bind(toggle: true)
} else {
cell.bind(toggle: false)
}
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LockScreenNumCollectionViewCell.identifier, for: indexPath) as! LockScreenNumCollectionViewCell
cell.bind(title: numPadComposition[indexPath.row])
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == lockScreenView.numsCollectionView {
switch numPadComposition[indexPath.row] {
case "AC":
userInPutPassword.value = ""
case "C":
if userInPutPassword.value.count != 0 {
let _ = userInPutPassword.value.popLast()
}
default:
if Int(passwordLength) > userInPutPassword.value.count {
userInPutPassword.value += numPadComposition[indexPath.row]
}
}
}
}
}
extension LockController: UICollectionViewDelegateFlowLayout {
// MARK: - extension UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
if collectionView == lockScreenView.passwordCollectionView {
let totalCellWidth = passwordCollectionviewItemSize.width * passwordLength
let totalSpacingWidth = passwordCollectionviewSpacing * (passwordLength - 1)
let leftInset = (collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
기존의 로직들도 재사용하기 위해 공통적으로 사용되는 부분을 찾아 LockController에 정의하였고 다양한 화면에서 LockController를 상속받아 일부분의 로직만 수정하여 반복되는 작업을 줄일 수 있었다.