Use TextField, List, and bindings to create dynamic content.
If you’ve ever typed on an iPhone, you’ve used a text field. In this tutorial, you’ll build an app that lets someone enter a list of names and then select one at random by tapping a button.
Apple Tutorial
TextField
를 이용해 이름을 입력받고 랜덤으로 입력된 이름 중 하나를 선택하는 기능 구현하기.
Tutorial View | My View |
---|---|
필요한 변수는 약 4가지였다.
1. 이름이 저장될 배열
2. 선택될 시 사라지는 설정의 온오프값
3. 입력받을 이름을 위한 변수
4. 랜덤으로 선택된 이름
그리고 이번엔 각 버튼과 리스트를 모두 별개의 View 파일로 나누었다. 따라서 필요한 변수를 전부 @State로 전달해주어야 했는데 생각보다 겹치는 변수가 많았고 조금 더 간단히 전달하기 위해 class
로 변수들을 묶게되었다.
final class NameModel{
var nameList: [String]
var isRemoveButtonOn: Bool
var name: String
var selectedName: String
init(nameList: [String], isRemoveButtonOn: Bool, name: String, selectedName: String) {
self.nameList = nameList
self.isRemoveButtonOn = isRemoveButtonOn
self.name = name
self.selectedName = selectedName
}
}
덕분에 다음과 같이 필요한 변수들을 간단히 전달할 수 있었고 특정 변수 하나만 필요한 경우엔 필요한 변수만 전달하여 사용했다.
지금 생각해보니 토글을 위한 Bool값만 따로 필요했기 때문에 NameModel에서 해당 값은 빼도 됐을 듯 하다.
PalList(nameModel: $nameModel)
NameField(nameModel: nameModel)
RemoveButton(isRemoveButtonOn: $nameModel.isRemoveButtonOn)
PickButton(nameModel:$nameModel)
다만 이렇게 바꾸니 TextField
에서 문제가 발생했다. 단순하게 상위View에서 @State
로 감싼 변수를 하위View에서 전달받았을 땐 TextField
에서 수정한 값이 잘 전달되었지만 nameModel.name을 바인딩했을 땐 TextField
에서 수정한 값이 전달되지 않았다.
이는 class로 NameModel을 선언한 부분에서 발생한 문제로 @State
로 값의 변경을 추적하려면 ObservableObject
프로토콜을 넣어주었어야 했다. 추가적으로 추적하려는 변수 앞에는 @Published
를 넣어야 했다. ObservableObject
프로토콜 사용을 위해선 Combie
또는 Foundation
을 import해주어야 했다.
다른 방법으로는 23년도에 추가된 SwfitData
의 @Model
프로퍼티래퍼를 class
에 붙이는 것으로 @Model
프로퍼티래퍼 안에 ObservableObject
가 포함되어 있어 더욱 간단하게 적용할 수 있었다.
스위프트에서 심볼을 넣을 때 사용하는 SF Symbol
에서는 심볼에 적용가능한 4가지 색상 모드를 지원한다. 또 앞선 주사위 굴리기에서 잠깐 나온 primary
, secondary
, tertiary
의 세 가지 레이어로 색상을 입힐 수 있다.
4가지 색상 모드는 Monochrome
, Hierarchical
, Palette
, Multicolor
로 이번에 사용된 hierarchical
만 간단히 알아보자면 primary
에 적용된 색상을 기준으로 각 레이어마다 다른 opacity를 적용해주는 모드다.
TextField
에서 별도의 버튼 없이 키보드의 return/enter 입력을 받을 때 실행될 코드를 입력해주는 modifier다.
.onSubmit {
if nameModel.name.isEmpty == false {
nameModel.nameList.append(nameModel.name)
nameModel.name = ""
}
}
return/enter를 입력받을 때 TextField
에 바인딩된 변수를 검사하고 빈 값이 아닐 때만 이름 배열에 추가한 뒤 다시 바인딩 된 변수를 초기화 하는 구문을 넣었다.
벨로그 애용 해주셔요 잘 읽고 갑니둥