[계산기] 이번엔 UI를 만들어보자

김하민·3일 전
1
post-thumbnail

Lv. 1

Lv. 1에선 계산기의 메인 숫자 라벨을 만들어 줄 겁니다.

음... 뭔가 글을 쓸 만한 껀덕지가 없네요.

일단 사용한 코드 먼저 봅시다.

코드

import UIKit
import SnapKit

class ViewController: UIViewController {

    let label = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureUI()
    }
  
    private func configureUI() {
        
        view.backgroundColor = .black
        
        label.text = "12345"
        label.font = .boldSystemFont(ofSize: 60)
        label.textColor = .white
        label.textAlignment = .right
        
        view.addSubview(label)

        label.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview().inset(30)
            make.top.equalToSuperview().inset(200)
            make.height.equalTo(100)
        }
        
    }

}

이렇게 썼고

이렇게 나왔습니다.

나중에 엄청 수정될 예정이니 다음으로 넘어가겠습니다.

Lv. 2 ~ 5

를 진행하기 전에...

다음 단계들을 쓱 훑어보니, 여러 생각이 들었습니다.

나열하자면:

  1. 버튼 위치를 차후에 변경하려면 번잡할 것 같다.
  2. 각 버튼 별 역할(숫자, 연산자, 변형자)에 따라 색상이 달라져야 하는데, 일일히 지정해 주기 싫다.
  3. 나중에 로직을 구현하면서 위에 말한 각 버튼 별 역할에 따라 동작을 달리 해줘야 할 것 같은데, 코드가 지저분해질 것 같다.

그래서 다음과 같은 조치를 취하였습니다:

1. 버튼 위치를 차후에 변경하기 쉽게 하자

buttons라는 [String]을 생성해 원하는 버튼을 배열 안에 제가 지정해주면 추후 버튼을 생성할 때 forEach를 사용해서 할 생각으로 만들었습니다.

뭐 이런↓ 느낌이죠?

// 이전 코드는 적절히 생략되었습니다.

class ViewController: UIViewController {
    
    let buttons: [String] = [
        "7", "8", "9", "+",
        "4", "5", "6", "-",
        "1", "2", "3", "*",
        "AC", "0", "=", "/",
    ]
    
// 이후 코드 또한 적절히 생략되었습니다.

나중에 할 때 잘... 되겠죠...?
(뉴비라해보기전까지될지안될지진짜모름)

2. 각 버튼 별 역할에 따라 색상이 자동으로 달라지게 하자

그러기 위해서 버튼의 유형을 먼저 enum으로 나누어주었습니다.

이렇게↓요.

enum ButtonRole {
    case number // 숫자 (0...9)
    case operation // 연산자 (operator를 쓸랬는데 예약어 크리...)
    case modifier // 변형자 (AC, 하나 지우기 등)
    case undefined // 미지의 존재 (몰라 이거 뭐야 무서워)
}

그 다음에 Button 클래스에서 입력받을 title에 따라 자동으로 지정되게 해주었습니다.

연산 프로퍼티(computed property)를 사용해서 말이죠.

class Button: UIButton {
    var title: String
    
    var buttonRole: ButtonRole {
        if self.title.isNumber {
            return .number
        }
        
        switch self.title {
        case "+", "-", "*", "/": return .operation
        case "AC", "+/-", "%": return .modifier
        default: return .undefined
        }
    }
    
 // 적절한 중략
 
 extension String {
    var isNumber: Bool {
        CharacterSet(charactersIn: self).isSubset(of: .decimalDigits)
    }    
}

여담이지만 변수명을 buttonRole 대신 role, type을 쓰려고 했는데 이미 UIButton에 있어서... 어쩔 수 없이 buttonRole으로 지었습니다.

이렇게 입력받은 title의 값을 이용해서 buttonRole을 지정해줬으니, 버튼 색 또한 자동으로 지정되게 해 볼까요?

class Button: UIButton {
    var title: String
    var buttonRole: ButtonRole { ... }
    
    var color: UIColor {
        switch self.buttonRole {
        // 일단은 임의의 색을 지정해줍니다.
        case .number: UIColor(red: 58/255,
                           green: 58/255,
                           blue: 58/255,
                           alpha: 1.0)
        case .operation: UIColor.systemOrange
        case .modifier: UIColor.systemGray
        case .undefined: UIColor.systemRed
        }
        
    }    
    // 후략
}

이렇게 또 한번 연산 프로퍼티를 이용하여 색이 적절히 지정되게 해 줍니다.

그럼 이걸 써먹어야 하겠죠?

이니셜라이징 후 버튼에 대한 세부사항을 설정해주는 메서드를 만듭시다.

// 이전 코드 생략

	init(title: String) {
        self.title = title
        super.init(frame: .zero)
        
        setButton()
    }
    
    func setButton() {
        setTitle(self.title, for: .normal)
        titleLabel?.font = .boldSystemFont(ofSize: 30)
        backgroundColor = color
        frame.size = CGSize(width: 80, height: 80)
        
        let action = #selector(onTap)
        addTarget(self, action: action, for: .touchDown)
    }
    
    @objc func onTap(_ sender: UIButton) {
        let title = sender.titleLabel?.text
        
        print("\(title ?? "error") tapped")
    }

요렇게요.

3. 로직을 구현하면서 위에 말한 각 버튼 별 역할에 따라 동작을 달리 해주자

는 위에서 설명이 되었네요.

넘어가겠습니다.

뭔가 성의 없다고 느껴지신다면 그게 정상입니다.

잠을 제대로 못 자서 제 정신이 아니거든요.

진짜 쓰러질 것 같으니
이만 자러가겠습니다.

(다음 시간에 계속...)

0개의 댓글