본문 바로가기

IOS

SwiftUI-100Days - WeSplit

728x90
반응형

 

전체 코드

import SwiftUI

struct ContentView: View {
    @State private var checkAmount = 0.0
    @State private var numberOfPeople: Int = 2
    @State private var tipPercentage = 20
    @FocusState private var amountIsFocused: Bool
    let tipPercentages = [10, 15, 20, 25, 0]
    
    var totalPerPerson: Double{
        let peopleCount = Double(numberOfPeople + 2)
        let tipSelection = Double(tipPercentage)
        
        let tipValue = checkAmount / 100 * tipSelection
        let grandTotal = checkAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount
        
        return amountPerPerson
    }
    
    var body: some View {
        NavigationView{
            Form{
                Section{
                    TextField("Amount", value: $checkAmount, format: .currency(code: Locale.current.currencySymbol ?? "USD"))
                        .keyboardType(.decimalPad)
                        .focused($amountIsFocused)
                    
                    Picker("Number Of People", selection: $numberOfPeople){
                        ForEach(2..<100){
                            Text($0, format: .percent)
                        }
                    }
                } header: {
                    Text("How much Tip?")
                }
                
                Section{
                    Picker("Tip percentage", selection: $tipPercentage){
                        ForEach(0..<101){
                            Text($0, format: .percent)
                        }
                    }
                } header: {
                    Text("Amount Per Person")
                }
                
                Section{
                    Text(totalPerPerson * Double(numberOfPeople+2), format: .currency(code: Locale.current.currencySymbol ?? "USD"))
                } header: {
                    Text("Total Amount + Tips")
                }
            }
            .navigationTitle("WeSplit")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar{
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Button("Done") {
                        amountIsFocused = false
                    }
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1.

@State로 선언된 변수는 View내에서 값이 변경될 때마다 뷰가 자동으로 다시 렌더링된다.

@State private var checkAmount = 0.0

TextField("Amount", value: $checkAmount, format: .currency(code: Locale.current.currencySymbol ?? "USD"))

앱 실행기 checkAmount의 값은 Double형의 0.0으로 할당되었지만 TextField에서 $checkAmount를 value로 설정하여 TextField에 입력을 하면 checkAmount의 값이 동적으로 변하며 뷰가 자동으로 다시 렌더링되는 것이다.

여기서 $의 의미는 @State로 선언하여 값이 변경될 수 있는 변수라는 의미를 가진다.

 

2.

@FocusState는 포커스를 처리하는데 사용되는 프로퍼티 래퍼이다. 

@FocusState private var amountIsFocused: Bool

TextField("Amount", value: $checkAmount, format: .currency(code: Locale.current.currencySymbol ?? "USD"))
                        .keyboardType(.decimalPad)
                        .focused($amountIsFocused)
                        
Button("Done"){
                        amountIsFocused = false
                    }

WeSplit에서는 TextField에 원하는 값을 입력 할때 나타나는 키보드를 숨기기위해 사용하였다.

TextField에 값을 입력하기 위해 focus되었을때 

.focused($amountIsFocused)

코드를 통해 amoutIsFocused의 값이 true로 값을 변경한다.

입력이 끝난 후에는 toolbar에 설정한 Done 버튼을 사용하여 false로 값을 변경하여 키보드를 숨길 수 있게된다.

 

Button("Done"){
                        amountIsFocused = false
                    }

 

3.

totalPerPerson 클로저는 computed property로 checkAmount, numberOfPeople, tipPercentage의 값들을 참조하여 계산된 결과값을 반환한다.

computed property는 다른 속성들의 값을 기반으로 값을 반환하기 때문에 다른 속성들의 값이 변할 때마다 자동으로 업데이트된다.

특이한 점으로는 프로퍼티에 할당된 값이 직접적으로 변하는 것이 아니기때문에 @state 프로퍼티를 사용하지 않았다.

var totalPerPerson: Double{
        // calculate the total per person here
        let peopleCount = Double(numberOfPeople + 2)
        let tipSelection = Double(tipPercentage)
        
        let tipValue = checkAmount / 100 * tipSelection
        let grandTotal = checkAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount
        
        return amountPerPerson
    }
    
 Text(totalPerPerson, format: .currency(code: Locale.current.currencySymbol ?? "USD"))

 

4. NavigationView는 뷰의 내부에 툴바와 제목을 제공한다.

NavigationView{
            Form{ ... }
            .navigationTitle("WeSplit")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Button("Done"){
                        amountIsFocused = false
                    }
                }
            }
        }

 

상단에 WeSplit 뷰의 제목을 제공하였다.

.navigationTitle("WeSplit")
.navigationBarTitleDisplayMode(.inline)

NavigationTitled의 스타일을 지정해주는 modifier로 .inline 형태로 설정하였다.

.toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Button("Done"){
                        amountIsFocused = false
                    }
                }
            }

NavigationView에 toolbar를 추가하였다. 

ToolbarItemGroup(placement: .keyboard)

placement: .keyboard를 사용하여 키보드의 상단에 Done 버튼을 설정하였다.

 

5. Picker는 다른 뷰를 선택할 수 있는 드롭다운 메뉴를 만들어준다.

Picker("Number Of Peopel", selection: $numberOfPeople) {
	ForEach(2..<100){
		Text("\($0) people")
        }

Picker 부분을 활성화(클릭)하게 되면 ForEach의 범위 내에서 값을 선택할 수 있다.

선택된 값은 selection에 설정한 numberOfPeople의 값으로 할당된다.

$0은 ForEach의 모든 값들을 간단하게 설정할 수 있도록 해준다.

 

반응형