목차
지난 4편에서 만든 LocalizedNumberFormatter를 사용하여 Textfield 예제를 만들고자 합니다.
en_US(English, United States)
숫자에서 ar(Arabic)
숫자로 변경final class SampleFieldModel: ObservableObject {
@Published var fieldViewModels: [LocalizedNumberFieldViewModel] = [
LocalizedNumberFieldViewModel(
index: 0,
placeHolder: "숫자를 입력해주세요",
text: "",
formatter: LocalizedNumberFormatter(from: .en_US, to: Locale.ko_KR),
keyboardType: .default
),
LocalizedNumberFieldViewModel(
index: 1,
placeHolder: "숫자를 입력해주세요",
text: "",
formatter: LocalizedNumberFormatter(from: .en_US, to: Locale.fr_GP),
keyboardType: .default
),
LocalizedNumberFieldViewModel(
index: 2,
placeHolder: "숫자를 입력해주세요",
text: "",
formatter: LocalizedNumberFormatter(from: .en_US, to: Locale.ne),
keyboardType: .default
),
LocalizedNumberFieldViewModel(
index: 3,
placeHolder: "숫자를 입력해주세요",
text: "",
formatter: LocalizedNumberFormatter(from: .en_US, to: Locale.ar),
keyboardType: .default
),
LocalizedNumberFieldViewModel(
index: 4,
placeHolder: "숫자를 입력해주세요",
text: "",
formatter: LocalizedNumberFormatter(from: .en_US, to: Locale.it_CH),
keyboardType: .default
)
]
}
@Published
Attributed로 지정합니다.en_US
ko_KR
, fr_GP
, ne
, ar
, it_CH
import SwiftUI
@main
struct LocalizedNumberFieldApp: App {
@StateObject var sampleModel = SampleFieldModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(sampleModel)
}
}
}
struct ContentView: View {
@EnvironmentObject var modelData: SampleFieldModel
var body: some View {
SampleList()
.environmentObject(modelData)
}
}
@EnvironmentObject
Attribute로 설정.import SwiftUI
struct SampleList: View {
@EnvironmentObject var modelData: SampleFieldModel
var body: some View {
List {
ForEach(modelData.fieldViewModels) {
SampleRow(dataSource: $0)
.environmentObject(modelData)
.buttonStyle(PlainButtonStyle())
}
}
}
}
import SwiftUI
struct SampleRow: View {
var dataSource: LocalizedNumberFieldViewModel
/// textfield endEditing 일 때 상태 받는 곳
@State private var endEditing: Bool = false
private var title: String {
return "🌎 from \(dataSource.formatter.fromLocale.identifier) to \(dataSource.formatter.toLocale.identifier)"
}
var body: some View {
VStack {
Spacer()
Text(title)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.system(size: 20.0, weight: .bold, design: .rounded))
HStack {
Spacer()
// ⭐️ use it!
LocalizedNumberFieldView(dataSource: dataSource, endEditing: $endEditing)
Button(
action: {
hideKeyboard() // extension 참고
},
label: {
Text("Button")
.font(.body)
.fontWeight(.bold)
.padding(5.0)
}
)
.background(Color.yellow)
Spacer()
}
// textfield endEditing되면 변환 결과 보여주기
Text(" result: \(endEditing ? dataSource.result.description : "none")")
.frame(maxWidth: .infinity, alignment: .leading)
.font(.system(size: 18.0, weight: .light, design: .rounded))
Spacer()
}
}
}
#if canImport(UIKit)
extension View {
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
#endif
import SwiftUI
struct LocalizedNumberFieldView: View {
@EnvironmentObject var modelData: SampleFieldModel
var dataSource: LocalizedNumberFieldViewModel
/// textfield endEditing 일 때 상태 변환
@Binding var endEditing: Bool
@State private var textfieldBorderColor: UIColor = .systemFill
var body: some View {
VStack {
HStack {
TextField(
dataSource.placeHolder,
text: $modelData.fieldViewModels[dataSource.index].text,
onEditingChanged: { onEditing in
if false == onEditing {
try? validate(text: dataSource.text)
}
endEditing = !onEditing
}
)
.keyboardType(dataSource.keyboardType)
.border(Color(textfieldBorderColor), width: 1)
}
}
}
/// 변환 결과값
private func validate(text: String) throws {
do {
let localizedNumber = try dataSource.formatter.localizedNumberString(from: text, style: .decimal)
setResult(text: localizedNumber, result: .success(from: text, to: localizedNumber))
} catch {
let formatterError = error as? LocalizedNumberFormatterError
setResult(text: text, result: .error(formatterError ?? .unknown))
throw error
}
}
private func setResult(text: String, result: LocalizedNumberFormatterResult) {
dataSource.result = result
textfieldBorderColor = result.isError ? .systemRed : .systemFill
}
}
func validate(text: String) throws
를 통해 변환onEditingChanged
The action to perform when the user begins editing text and after the user finishes editing text. The closure receives a Boolean value that indicates the editing status: true when the user begins editing, false when they finish.
LocalizedNumberFormatterResult
) 업데이트@State private var endEditing: Bool
이 업데이트