스파르타 코딩 클럽 - iOS 스타터 6기/본 캠프

24. 스파르타 코딩 클럽 - 계산기 UI 만들어보기 (CodeBase) Lv1 ~ Lv5

seongpil Heo 2025. 3. 31. 19:01

 🧑‍💻 코드베이스 UI로 계산기 앱 만들기

입문 강의에서 배운 것들을 복습하며 지금까지 Playground에서 로직만 구현했던 계산기에 UI를 더해, 실제 앱으로 완성해 봅시다.


 📋 프로젝트 개요

이 과제에서는 간단한 약식 계산기 앱을 개발합니다.

  • 소수점을 고려하지 않은, 정수형 계산만 하며
  • 모든 연산 버튼을 클릭할 때마다 계산이 이루어지도록 하지는 않으며
  • 등호 버튼 (`=`) 을 클릭했을 때만 연산이 이루어지도록 합니다.
  • 수식 문자열이 들어왔을 때 이를 계산해 주는 Swift의 기본 제공 기능을 활용합니다.

일반적인 계산기 앱은 구현이 꽤 복잡합니다. 예를 들어 소수점이 들어오는 경우를 고려, 입력된 값의 자릿수가 너무 커서 지정한 라벨의 영역을 넘어가는 경우를 고려해야 하며, 세 자릿수마다 쉼표를 찍어줘야 하며, 모든 연산 버튼을 클릭할 때마다 계산이 이루어져야 합니다.


 구현기능 가이드 공통 사항

  • UILabel 로 숫자를 표시합니다.
  • UIButton 으로 숫자와 연산 버튼들을 만듭니다.
  • UIStackView 로 버튼들을 규칙성 있게 배치합니다.
  • AutoLayout 을 활용해서 레이아웃을 설정합니다.
  • backgroundColor , layer.cornerRadius 등 다양한 속성들을 활용합니다.
  • UIButtonaddTarget 혹은 IBAction 으로 버튼을 클릭했을 때 이벤트를 설정합니다.

 📝 필수 구현기능 가이드


 🧑‍💻 Lv5까지의 구현 코드

//
//  ViewController.swift
//  CalculatorUI
//
//  Created by 허성필 on 3/28/25.
//

import UIKit
import SnapKit

class ViewController: UIViewController {
    let label = UILabel() // label 생성
    let verticalStackView = UIStackView()
    
    let buttonLabels = [["7", "8", "9", "+"],["4", "5", "6", "-"],
                        ["1", "2", "3", "*"], ["AC", "0", "=", "/"]]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        makeLabelUI() // 라벨 생성
        makeVerticalStackView() // 1개의 Vertical 스택 뷰를 생성
        for i in buttonLabels { // 4개의 Horizontal 스택 뷰를 생성
            makeHorizontalStackView(i) //
        }
    }
    
    private func makeLabelUI() { // 숫자 라벨 만들기
        view.backgroundColor = .black
        label.textColor = .white
        label.text = "12345"
        label.textAlignment = .right
        label.font = .boldSystemFont(ofSize: 60)
        
        view.addSubview(label)
        
        label.snp.makeConstraints{ make in
            make.leading.equalToSuperview().offset(30)
            make.trailing.equalToSuperview().offset(-30)
            make.top.equalToSuperview().offset(200)
            make.height.equalTo(100)
        }
    }
    
    private func makeVerticalStackView() { // Vertical 스택 뷰를 생성 함수
        verticalStackView.axis = .vertical
        verticalStackView.backgroundColor = .black
        verticalStackView.spacing = 10
        verticalStackView.distribution = .fillEqually
        
        view.addSubview(verticalStackView)
        
        verticalStackView.snp.makeConstraints{ make in
            make.width.equalTo(350)
            make.top.equalTo(label.snp.bottom).offset(60)
            make.centerX.equalToSuperview()
        }
    }
    
    private func makeButton(_ text: String) -> UIButton { // 버튼을 만드느 함수
        let button = UIButton()
        
        button.setTitle(text, for: .normal)
        button.titleLabel?.font = .boldSystemFont(ofSize: 30)
        button.layer.cornerRadius = 40
        
        // 해당 text가 들어오면 backgroundColor를 orange색으로 변경
        if ["+", "-", "*", "/", "=", "AC"].contains(text) {
            button.backgroundColor = .orange
        } else {
            button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
        }
        
        button.snp.makeConstraints{ make in
            make.width.height.equalTo(80)
        }
        
        return button
    }
    
    // Horizontal 스택 뷰를 생성 함수
    private func makeHorizontalStackView(_ buttonLabel: [String]) {
        
        let horizontalStackView = UIStackView()
        
        verticalStackView.addArrangedSubview(horizontalStackView)
        
        horizontalStackView.axis = .horizontal
        horizontalStackView.backgroundColor = .black
        horizontalStackView.spacing = 10
        horizontalStackView.distribution = .fillEqually
        
        horizontalStackView.snp.makeConstraints{ make in
            make.height.equalTo(80)
        }
        
        for i in buttonLabel {
            // for문
            horizontalStackView.addArrangedSubview(makeButton(i)) // 4번 반복
            // 메이크 버튼
        }
        
        
    }
}

Simulator


  🎯 Trouble Shooting

Lv4에서 버튼의 배경색을 변경하기 위해서 처음에 contains 함수를 사용하였는데

// 초기 구현 코드
if text.contains("+, -, *, /, =, AC") {
        button.backgroundColor = .orange
    }
        

// 개선 구현 코드
if ["+", "-", "*", "/", "=", "AC"].contains(text) {
        button.backgroundColor = .orange
    }

 

처음에는 해당 연산자 기호들이 포함되면 버튼의 배경색이 오렌지 색으로 변경되는 줄 알았지만 코드가 동작하지 않았다.

contains 메서드가 해당 문자열을 포함하는지를 확인하는 것이지, 특정 단어(또는 문자)가 포함되는지를 판단하는 방식이 올바르지 않기 때문에 내 코드가 동작하지 않았다.

 

그래서 아래와 같이 코드를 변경하였는데  배열에 있는 연산 기호들이 text에 포함이 되어 있다면

버튼의 배경색을 orange 색으로 변경하도록 수정하였다.

 

개선 코드로 변경하니 내가 원하는 대로 연산 기호들의 버튼의 배경색이 잘 변경되었다.


 ✓ TIL

Lv5까지 코드를 구현하면서 처음 해본 스택뷰를 코드 베이스로 구현하는 것이 쉽지 않았다.

버튼을 만드는 함수를 만들고 Horizontal 스택뷰를 만드는 함수와 Vertical 스택뷰를 만드는 함수를 만들어서

For문을 돌려서 4줄의 Horizontal 스택뷰를 구현하였다.

이 부분에서도 살짝 어려움이 있었지만 잘 정리해서 코드를 완성했다.

 

수요일까지 Lv8을 목표로 개발을 해야겠다.