Ch 3. 앱 개발 입문 주차 과제
⎮ Lv. 4 ~ 5
Lv 4. 연산 버튼 (+, -, *, /, AC, =) 들은 색상을 orange 로 설정.
* 개발 효율성을 위한 팁 : 버튼을 만드는 func makeButton이라는 메서드가 있었고 인자로 titleValue: String, action: Selector, backgroundColor: UIColor가 있었으면 편했을 것
Lv 5. 버튼을 동그랗게 만들기
Lv.4에서 작성한 코드
class ViewController: UIViewController {
private var number = 12345
let label = UILabel()
let button = UIButton()
private var titles = [["7", "8", "9", "+"], ["4", "5", "6", "-"], ["1", "2", "3", "*"], ["AC", "0", "=", "/"]]
private var verticalStackView = UIStackView()
private var stackView1 = UIStackView()
private var stackView2 = UIStackView()
private var stackView3 = UIStackView()
private var stackView4 = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
setLabel()
setUI()
}
private func setLabel() {
view.backgroundColor = .black
label.text = "\(number)"
label.textAlignment = .right
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 60)
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
label.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
label.heightAnchor.constraint(equalToConstant: 100)
])
}
func setUI() {
let setButton1 = setButton(titles[0], button)
let setButton2 = setButton(titles[1], button)
let setButton3 = setButton(titles[2], button)
let setButton4 = setButton(titles[3], button)
stackView1 = makeHorizontalStackView(setButton1)
stackView2 = makeHorizontalStackView(setButton2)
stackView3 = makeHorizontalStackView(setButton3)
stackView4 = makeHorizontalStackView(setButton4)
let arrStackView = fourStackView()
verticalStackView = makeVerticalStackView(arrStackView)
}
// 타이틀이 바뀌어 적용되는 버튼을 만들고 배열로 묶어주는 함수
private func setButton(_ titles : [String], _ button: UIButton) -> [UIButton] {
var arrButtons: [UIButton] = []
let operate = ["+", "-", "*", "AC", "=", "/"]
for title in titles {
let button = UIButton()
button.setTitle(title, for: .normal)
// 만약에 title이 operate의 요소를 포함하고 있지 않으면
if !titles.contains(operate) {
button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
} else {
button.backgroundColor = UIColor.orange
}
button.titleLabel?.font = .boldSystemFont(ofSize: 30)
button.layer.cornerRadius = 40
arrButtons.append(button)
}
return arrButtons
}
// 4개의 버튼 배열을 묶어서 1개의 스택뷰로 만들어주는 함수
private func makeHorizontalStackView(_ views: [UIButton]) -> UIStackView {
let horizontalStackView = UIStackView()
horizontalStackView.axis = .horizontal
horizontalStackView.backgroundColor = .black
horizontalStackView.spacing = 10
horizontalStackView.distribution = .fillEqually
horizontalStackView.addArrangedSubview(views[0])
horizontalStackView.addArrangedSubview(views[1])
horizontalStackView.addArrangedSubview(views[2])
horizontalStackView.addArrangedSubview(views[3])
view.addSubview(horizontalStackView)
horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
horizontalStackView.heightAnchor.constraint(equalToConstant: 80)
])
return horizontalStackView
}
// 4개의 스택뷰를 묶어서 배열로 리턴하는 함수
private func fourStackView() -> [UIStackView] {
let arrStackView = [stackView1, stackView2, stackView3, stackView4]
return arrStackView
}
// 스택뷰 배열을 받아서 UIStackView로 리턴하는 함수 (여기서 Vertical StackView로 전환)
private func makeVerticalStackView(_ stackViews: [UIStackView]) -> UIStackView {
verticalStackView.axis = .vertical
verticalStackView.backgroundColor = .black
verticalStackView.spacing = 10
verticalStackView.distribution = .fillEqually
verticalStackView.addArrangedSubview(stackViews[0])
verticalStackView.addArrangedSubview(stackViews[1])
verticalStackView.addArrangedSubview(stackViews[2])
verticalStackView.addArrangedSubview(stackViews[3])
view.addSubview(verticalStackView)
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
verticalStackView.widthAnchor.constraint(equalToConstant: 350),
verticalStackView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 60),
verticalStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
return verticalStackView
}
}
나는 if문을 사용해서 컬러의 변경을 반영하고자 했다.
야심차게 if문을 작성하고 빌드해보니, 색상 변경이 적용되지 않았다.
⎮ 트러블 슈팅
let operate = ["+", "-", "*", "AC", "=", "/"]
for title in titles {
let button = UIButton()
button.setTitle(title, for: .normal)
// 만약에 title이 operate의 요소를 포함하고 있지 않으면
if !titles.contains(operate) {
button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
} else {
button.backgroundColor = UIColor.orange
}
button.titleLabel?.font = .boldSystemFont(ofSize: 30)
button.layer.cornerRadius = 40
arrButtons.append(button)
}
이 부분의 코드를 뜯어보자.
titles에 ["7", "8", "9", "+"]가 있다면, title에는 "7", "8", "9", "+"가 각각 들어간다.
첫번째 반복 때 title은 "7"이다.
그렇다면 operate에는 뭐가 들어가 있을까?
operate에는 연산자 전부가 들어가 있다.
따라서 하나씩 비교하는 것이 아니라 "7"과 연산자 전체와 비교하는 것이라 조건이 항상 false가 된다.
operate를 하나씩 비교하게 만들면, 아래처럼 작성할 수 있다.
for title in titles {
let button = UIButton()
button.setTitle(title, for: .normal)
// 만약에 title이 operate의 요소를 포함하고 있지 않으면
if !operate.contains(title) {
button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
} else {
button.backgroundColor = UIColor.orange
}
button.titleLabel?.font = .boldSystemFont(ofSize: 30)
button.layer.cornerRadius = 40
arrButtons.append(button)
}
.contains를 통해 operate의 요소를 확인하고, 해당 요소들과 각각 title을 비교하게 하는 것이다.
이렇게 하면 다음과 같은 빌드 결과를 얻을 수 있다.
Lv.4~ 5에서 최종 작성한 코드
class ViewController: UIViewController {
var number = 0
let label = UILabel()
let button = UIButton()
private var titles = [["7", "8", "9", "+"], ["4", "5", "6", "-"], ["1", "2", "3", "*"], ["AC", "0", "=", "/"]]
private var verticalStackView = UIStackView()
private var stackView1 = UIStackView()
private var stackView2 = UIStackView()
private var stackView3 = UIStackView()
private var stackView4 = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
setLabel()
setUI()
}
private func setLabel() {
view.backgroundColor = .black
label.text = "\(number)"
label.textAlignment = .right
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 60)
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
label.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
label.heightAnchor.constraint(equalToConstant: 100)
])
}
func setUI() {
let setButton1 = setButton(titles[0], #selector(buttonTapped), button)
let setButton2 = setButton(titles[1], #selector(buttonTapped), button)
let setButton3 = setButton(titles[2], #selector(buttonTapped), button)
let setButton4 = setButton(titles[3], #selector(buttonTapped), button)
stackView1 = makeHorizontalStackView(setButton1)
stackView2 = makeHorizontalStackView(setButton2)
stackView3 = makeHorizontalStackView(setButton3)
stackView4 = makeHorizontalStackView(setButton4)
let arrStackView = fourStackView()
verticalStackView = makeVerticalStackView(arrStackView)
}
// 타이틀이 바뀌어 적용되는 버튼을 만들고 배열로 묶어주는 함수
private func setButton(_ titles : [String], _ button: UIButton) -> [UIButton] {
var arrButtons: [UIButton] = []
let operate = ["+", "-", "*", "AC", "=", "/"]
for title in titles {
let button = UIButton()
button.setTitle(title, for: .normal)
// 만약에 title이 operate의 요소를 포함하고 있지 않으면
if !operate.contains(title) {
button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
} else {
button.backgroundColor = UIColor.orange
}
button.titleLabel?.font = .boldSystemFont(ofSize: 30)
button.layer.cornerRadius = 40
arrButtons.append(button)
}
return arrButtons
}
// 4개의 버튼 배열을 묶어서 1개의 스택뷰로 만들어주는 함수
private func makeHorizontalStackView(_ views: [UIButton]) -> UIStackView {
let horizontalStackView = UIStackView()
horizontalStackView.axis = .horizontal
horizontalStackView.backgroundColor = .black
horizontalStackView.spacing = 10
horizontalStackView.distribution = .fillEqually
horizontalStackView.addArrangedSubview(views[0])
horizontalStackView.addArrangedSubview(views[1])
horizontalStackView.addArrangedSubview(views[2])
horizontalStackView.addArrangedSubview(views[3])
view.addSubview(horizontalStackView)
horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
horizontalStackView.heightAnchor.constraint(equalToConstant: 80)
])
return horizontalStackView
}
// 4개의 스택뷰를 묶어서 배열로 리턴하는 함수
private func fourStackView() -> [UIStackView] {
let arrStackView = [stackView1, stackView2, stackView3, stackView4]
return arrStackView
}
// 스택뷰 배열을 받아서 UIStackView로 리턴하는 함수 (여기서 Vertical StackView로 전환)
private func makeVerticalStackView(_ stackViews: [UIStackView]) -> UIStackView {
verticalStackView.axis = .vertical
verticalStackView.backgroundColor = .black
verticalStackView.spacing = 10
verticalStackView.distribution = .fillEqually
verticalStackView.addArrangedSubview(stackViews[0])
verticalStackView.addArrangedSubview(stackViews[1])
verticalStackView.addArrangedSubview(stackViews[2])
verticalStackView.addArrangedSubview(stackViews[3])
view.addSubview(verticalStackView)
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
verticalStackView.widthAnchor.constraint(equalToConstant: 350),
verticalStackView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 60),
verticalStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
return verticalStackView
}
}
⎮ Lv. 6
Lv 6.
- 이제 기본 텍스트는 “12345” 가 아닌 “0” 이 되도록 합니다.
- 기본으로 라벨에 노출되어있던 텍스트 오른쪽에 버튼을 클릭하면 그 버튼의 값이 추가되도록 합니다.
예를들어 설명하면 맨처음 기본값 0 그 다음 1 클릭했음 → 표시되는 값은 01
그 다음 2 클릭했음 → 표시되는 값은 012
그 다음 + 클릭했음 → 표시되는 값은 012+
그 다음 3 클릭했음 → 표시되는 값은 012+3
* 하지만 012 라는 값은 이상합니다.
맨 앞자리가 0 인 숫자라면, 0을 지우고 표현하도록 합니다.
예를들면, 012 → 12 가 되어야 합니다.
class ViewController: UIViewController {
var number = "0"
let label = UILabel()
let button = UIButton()
private var titles = [["7", "8", "9", "+"], ["4", "5", "6", "-"], ["1", "2", "3", "*"], ["AC", "0", "=", "/"]]
private var verticalStackView = UIStackView()
private var stackView1 = UIStackView()
private var stackView2 = UIStackView()
private var stackView3 = UIStackView()
private var stackView4 = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
setLabel()
setUI()
}
private func setLabel() {
view.backgroundColor = .black
label.text = "\(number)"
label.textAlignment = .right
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 60)
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
label.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
label.heightAnchor.constraint(equalToConstant: 100)
])
}
func setUI() {
let setButton1 = setButton(titles[0], #selector(buttonTapped), button)
let setButton2 = setButton(titles[1], #selector(buttonTapped), button)
let setButton3 = setButton(titles[2], #selector(buttonTapped), button)
let setButton4 = setButton(titles[3], #selector(buttonTapped), button)
stackView1 = makeHorizontalStackView(setButton1)
stackView2 = makeHorizontalStackView(setButton2)
stackView3 = makeHorizontalStackView(setButton3)
stackView4 = makeHorizontalStackView(setButton4)
let arrStackView = fourStackView()
verticalStackView = makeVerticalStackView(arrStackView)
}
// 타이틀이 바뀌어 적용되는 버튼을 만들고 배열로 묶어주는 함수
private func setButton(_ titles : [String], _ action: Selector, _ button: UIButton) -> [UIButton] {
var arrButtons: [UIButton] = []
let operate = ["+", "-", "*", "AC", "=", "/"]
for title in titles {
let button = UIButton()
button.addTarget(self, action: action, for: .touchDown)
button.setTitle(title, for: .normal)
// 만약에 title이 operate의 요소를 포함하고 있지 않으면
if !operate.contains(title) {
button.backgroundColor = UIColor(red: 58/255, green: 58/255, blue: 58/255, alpha: 1.0)
} else {
button.backgroundColor = UIColor.orange
}
button.titleLabel?.font = .boldSystemFont(ofSize: 30)
button.layer.cornerRadius = 40
arrButtons.append(button)
}
return arrButtons
}
// 4개의 버튼 배열을 묶어서 1개의 스택뷰로 만들어주는 함수
private func makeHorizontalStackView(_ views: [UIButton]) -> UIStackView {
let horizontalStackView = UIStackView()
horizontalStackView.axis = .horizontal
horizontalStackView.backgroundColor = .black
horizontalStackView.spacing = 10
horizontalStackView.distribution = .fillEqually
horizontalStackView.addArrangedSubview(views[0])
horizontalStackView.addArrangedSubview(views[1])
horizontalStackView.addArrangedSubview(views[2])
horizontalStackView.addArrangedSubview(views[3])
view.addSubview(horizontalStackView)
horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
horizontalStackView.heightAnchor.constraint(equalToConstant: 80)
])
return horizontalStackView
}
// 4개의 스택뷰를 묶어서 배열로 리턴하는 함수
private func fourStackView() -> [UIStackView] {
let arrStackView = [stackView1, stackView2, stackView3, stackView4]
return arrStackView
}
// 스택뷰 배열을 받아서 UIStackView로 리턴하는 함수 (여기서 Vertical StackView로 전환)
private func makeVerticalStackView(_ stackViews: [UIStackView]) -> UIStackView {
verticalStackView.axis = .vertical
verticalStackView.backgroundColor = .black
verticalStackView.spacing = 10
verticalStackView.distribution = .fillEqually
verticalStackView.addArrangedSubview(stackViews[0])
verticalStackView.addArrangedSubview(stackViews[1])
verticalStackView.addArrangedSubview(stackViews[2])
verticalStackView.addArrangedSubview(stackViews[3])
view.addSubview(verticalStackView)
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
verticalStackView.widthAnchor.constraint(equalToConstant: 350),
verticalStackView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 60),
verticalStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
return verticalStackView
}
@objc
private func buttonTapped(_ sender: UIButton) {
guard let title = sender.currentTitle else { return }
if title != "=" {
number += title
if number.first == "0" {
number.removeFirst()
}
label.text = "\(number)"
}
}
}
'스파르타코딩 클럽 > 개인과제' 카테고리의 다른 글
16. 스파르타 코딩클럽 [본캠프 - 계산기 앱 : 정수기(6)] (0) | 2025.04.01 |
---|---|
15. 스파르타 코딩클럽 [본캠프 - 계산기 앱 : 정수기(5)] (0) | 2025.03.31 |
13. 스파르타 코딩클럽 [본캠프 - 계산기 앱 : 정수기(3)] (0) | 2025.03.28 |
12. 스파르타 코딩클럽 [본캠프 - 계산기 앱 : 정수기(2)] (0) | 2025.03.27 |
11. 스파르타 코딩클럽 [본캠프 - 계산기 앱 : 정수기] (0) | 2025.03.26 |