본문 바로가기
Project/ReceiptMind

💰 iOS 가계부 UI 구현기 – 선택된 항목에 따라 separator 색상 바꾸기

by 밤새는 탐험가89 2025. 7. 17.
728x90
SMALL

✅ 목적 정리

  1. TransactionType (수입/지출) 선택 시
    • .income → .systemGreen
    • .expense → .systemRed
  2. 이 타입 선택이 되면,
    • 자동으로 다음 입력 필드인 날짜(Date) 필드의 valueLabel이 선택된 것처럼 처리됨
    • 이때 해당 셀의 separator 색상이 타입에 따라 바뀜
  3. 이후 사용자가 금액(Amount), 분류(Category) 필드의 valueLabel을 탭하면
    • 해당 셀의 separator가 강조 색상으로 바뀌고
    • 이전에 선택된 셀은 강조 해제되어 .secondaryLabel 색상으로 복귀됨

🧱 구성된 컴포넌트 및 구조

🔹 Enum 정의

enum TransactionType {
    case income, expense
}

enum AddSection: Int, CaseIterable {
    case addType, date, amount, category, memo

    var title: String {
        switch self {
        case .date: return "날짜"
        case .amount: return "금액"
        case .category: return "분류"
        default: return ""
        }
    }
}

 

💡 구현 흐름 정리

1. 사용자가 AddTypeCell에서 .income 또는 .expense 선택

selectedTransactionType 변경
→ 자동으로 selectedIndexPath = .date 섹션 선택
→ addTableView.reloadData()로 리프레시
→ date 셀이 선택된 것처럼 강조 표시


2. 테이블의 각 셀은 공용 AddCustomCell 사용

  • 이 안에는 valueLabel, separator가 존재
  • updateSeparatorColor(isSelected:transactionType:) 메서드로 선택 여부/타입에 따라 색상 변경

3. 이후 다른 셀을 선택하면

  • selectedIndexPath 갱신
  • 전체 reload를 통해 "새로 선택된 셀만 강조, 이전은 해제" 구조 유지

 

🔧 핵심 코드 설명

✅ AddTypeCell.swift

// MARK: - Action Method
@objc private func buttonTapped(_ sender: UIButton) {
    selectedType = sender.tag == 0 ? .income : .expense
    delegate?.didSelectTransactionType(selectedType!)
}
  • 각 버튼이 눌리면 selectedType에 선택된 type의 정보를 전달 
  • delegate 패턴을 통해 메서드를 동작 
protocol AddTypeCellDelegate: AnyObject {
    func didSelectTransactionType(_ type: TransactionType)
}
  • 어떤 type의 버튼이 눌렸는지 정보를 전달할 목적의 delegate 패턴 구현
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let section = AddSection(rawValue: indexPath.section) else { fatalError("Invalid section") }

    switch section {
    case .addType:
        guard let cell = tableView.dequeueReusableCell(withIdentifier: AddTypeCell.reuseIdentifier, for: indexPath) as? AddTypeCell else { return UITableViewCell() }
        cell.delegate = self
        cell.selectionStyle = .none
        cell.configure(selectedType: selectedTransactionType)
        return cell
    ...
  • AddTypeCell의 상위 뷰인 AddTransactionViewController에서 해당 셀을 통해 tableview를 구현
  • cell의 delegate를 AddTransactionViewController로 설정 
extension AddTransactionViewController: AddTypeCellDelegate {
    func didSelectTransactionType(_ type: TransactionType) {
        selectedTransactionType = type
    }
}
  • AddTypeCell에서 선택한 type의 정보를 상위 뷰인 AddTransactionViewController에 전달함에 따라 didSelectTransactionType 메서드를 통해 데이터 전달 
class AddTransactionViewController: UIViewController {
    
    
    // MARK: - Variable
        private var selectedTransactionType: TransactionType = .expense {
        didSet {
            // 수입 / 지출 버튼이 선택되면 자동으로 date 섹션이 선택된 걸로 간주
            selectedIndexPath = IndexPath(row: 0, section: AddSection.date.rawValue)
            updateTitle()
            self.addTableView.reloadData()
        }
    }
    private var selectedIndexPath: IndexPath?
  • selectedTransactionType 에 프로퍼티 감시자를 통해 값의 변화에 따라 메서드 실행
  • selectedIndexPath는 어떤 셀이 "선택되었다" 라는 정보를 저장
  • IndexPath(row: 0, section: AddSection.date.rawValue) 
    • row 0: AddSection.date 섹션의 첫 번째 셀 (현재 모든 섹션에는 1개의 셀만 있으므로 항상 0)
    • section: AddSection.date.rawvalue: 날자(Date) 섹션에 해당

👉 수입/지출 버튼을 탭하면

→ 자동으로 "날짜(Date)" 셀이 선택된 것처럼 처리하고
→ separator가 수입이면 초록색, 지출이면 빨간색으로 바뀌게 되는 겁니다.

 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let section = AddSection(rawValue: indexPath.section) else { fatalError("Invalid section") }
        
        switch section {
        
        case .date, .amount, .category:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: AddCustomCell.reuseIdentifier, for: indexPath) as? AddCustomCell else { return UITableViewCell() }
            cell.configure(title: section.title)
            cell.selectionStyle = .none
            cell.delegate = self
            
            let isSelected = (indexPath == selectedIndexPath)
            cell.updateSeparatorColor(
                isSelected: isSelected,
                transactionType: selectedTransactionType
            )
            
            // 셀의 valueLabel 탭 제스처 연결
            cell.onValueLabelTapped = { [weak self] in
                self?.selectedIndexPath = indexPath
                self?.addTableView.reloadData()
                // 여기에 calendarView 또는 numberPad 띄우는 로직도 추가
            }
  • 각 case에 따라 선택 유무에따라 cell에 UI 변경
  • onValueTapped: AddCustomCell 에서 선언한 클로저로써, valueLabel이 탭 되었을 때 이를 감지하여 눌렸다는 정보를 전달
    // ✅ AddCustomCell 에서 구현
    
    func updateSeparatorColor(isSelected: Bool, transactionType: TransactionType) {
        if isSelected {
            switch transactionType {
            case .income:
                seperator.backgroundColor = .systemGreen
            case .expense:
                seperator.backgroundColor = .systemRed
            }
        } else {
            seperator.backgroundColor = .secondaryLabel
        }
    }

 

728x90
LIST