SwiftUI로 Placeholder가 존재하는 TextField 설계 팁 (UIKit호환)
최근에는 SwiftUI와 UIKit을 정말 많이 혼용해서 사용하고 있음.
특히 몇몇 컴포넌트들은 SwiftUI로 작성한 것들을 UIKit에서 가져다가 사용하는 컴포넌트들이 많은데, 서로 손쉽게 사용할 수 있도록 설계.
글의 순서
- 구현 결과 스크린샷
- 구현 예시 코드
- SwiftUI Usage
- UIKit Usage
구현 결과 스크린샷
구현 예시 코드
구현 포인트
- @State, @Binding을 외부에 직접 노출시키는 것이 아닌 Delegate를 통해 이벤트를 전달함.
- 장점: UIKit에서 공통된 코드 규칙으로 편리하게 사용할 수 있음.
import SwiftUI
/// 리스트에서 사용하는 검색 필드
struct SearchFiled: View {
struct InitialState {
/// 플레이스홀더 기본 값
var placeholderText: String
/// 색상
var appearance: Appearance
struct Appearance {
/// 돋보기 색상
var magnifyingglassImage: Color
/// xmark 색상
var xmarkImage: Color
/// 텍스트 필드 배경 색상
var textFieldBackground: Color
/// 텍스트 필드 강조 색상
var textFieldAccent: Color
/// 플레이스 홀더 색상
var placeHolderText: Color
}
}
/// 검색할 단어
@State private var searchText: String = ""
enum DelegateAction {
/// 전체 지우는 버튼 탭
case clearButtonTaaped
/// 검색 단어가 변화했을 때
case onChangeSearchText(oldValue: String, newValue: String)
/// 텍스트 필드 onSubmit
case onSubmitTextField
}
/// 초기값
private var initialState: InitialState
/// 외부로 내보낼 액션
private(set) var delegate: ((DelegateAction) -> ())?
init(
initialState: InitialState,
delegate: ((DelegateAction) -> Void)? = nil
) {
self.delegate = delegate
self.initialState = initialState
}
var body: some View {
HStack {
Image(systemName: "magnifyingglass")
.foregroundStyle(.gray)
ZStack(alignment: .leading) {
if searchText.isEmpty {
Text(initialState.placeholderText)
.foregroundStyle(initialState.appearance.placeHolderText)
}
TextField("", text: $searchText)
.accentColor(initialState.appearance.textFieldAccent)
.onSubmit {
delegate?(.onSubmitTextField)
}
.onChange(of: searchText) { newValue in
delegate?(.onChangeSearchText(oldValue: searchText, newValue: newValue))
}
}
if !searchText.isEmpty {
Button {
searchText = ""
delegate?(.clearButtonTaaped)
} label: {
withAnimation(.smooth) {
Image(systemName: "xmark.circle")
.foregroundStyle(initialState.appearance.xmarkImage)
}
}
}
}
.padding(.horizontal, 12)
.frame(height: 40)
.background(
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(initialState.appearance.textFieldBackground)
)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(
Color.clear
)
}
}
SwiftUI 사용법 (Usage)
SwiftUI의 경우 해당 코드처럼 작성해 사용
- 초기 상태는 initialState로 주입하며, @Binding 대신 내부 이벤트를 delegate를 활용해 처리
- 이렇게 할 경우 외부에서 굳이 처리할 필요 없는 @State, Publisher를 작성하도록 강제하지 않아도 되어서 외부 코드가 더 깔끔해짐.
UIKit 사용법 (Usage)
UIKit의 경우 해당 코드처럼 작성해 사용
- UIKit도 SwiftUI와 동일하게 사용할 수 있고 이벤트는 viewModel로 넘겨 처리 가능
'project > 개발 업무' 카테고리의 다른 글
UICollectionView Crashes on iOS 18 with Xcode 16: Troubleshooting Guide (0) | 2024.11.22 |
---|---|
Combine ReadOnly Publisher (0) | 2024.11.20 |
[Xcode 16 Beta] Could not download and install iOS 18.0 Simulator runtime with Xcode 16.0 beta (0) | 2024.06.12 |
[XCode 15.0 beta] Preview Macro Bug (0) | 2023.06.08 |
Lottie 리소스 문제로 앱이 초기화되는 현상 (0) | 2022.07.12 |