SwiftUI 기반인 앱을 구현하면서 UIKit에서는 지원하지만 SwiftUI에서는 지원하지 않는 뷰들이 아직 존재한다는 것을 알게 되었다.
그럴 때 UIKit에서 제공하는 뷰를 SwiftUI에서 사용할 수 있도록 래핑 해주는 기능의 프로토콜이 바로 UIViewRepresentable이다.
SwiftUI에서 UIKit 사용하기 UIViewRepresentable (1) | TextField에서 clear button 사용하고 싶다면
SwiftUI에서 UIKit 사용하기 UIViewRepresentable(2) | @Binding 이란? Coordinator 란?
# 🥨 UIViewRepresentable
SwiftUI에서 UIKit을 쓸 수 있도록 해주는 프로토콜이며, 사용 시 만들고 싶은 구조체에서 UIViewRepresentable 프로토콜을 채택해 주고 필수 함수인 makeUIView(context:) -> UIView와updateUIView(:context:) 를 추가해 준다
- makeUIView(context:) -> UIView
처음으로 뷰를 생성할 때 호출하는 메서드. 여기에서는 원하는 UIView를 리턴해주면 된다. 예를 들어, UITextField를 뷰로 띄워주고 싶다면 UITextField를 리턴타입으로 지정해 주면 된다.
- updateUIView(:context:)
변경사항이 발생할 때마다 호출되는 메서드이다.
# 🥨 UIViewRepresentable 활용해서 UITextField 그리기
SwiftUI 앱을 구현하다가 UIKit의 UITextField를 활용해서 앱에 그려주어야 하는 상황이라고 가정하자. 그럴 때 UIViewRepresentable프로토콜을 채택하는 구조체를 생성해서 뷰를 그려줄 수 있다.
struct UIKitTextField : UIViewRepresentable {
private let textField = UITextField()
func makeUIView(context: UIViewRepresentableContext<UIKitTextField>) -> UITextField{
//textField의 style
textField.backgroundColor = .gray
textField.layer.cornerRadius = 3
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<UIKitTextField>){
print("updateUIView")
}
}
실제 사용해 줄 때는 SwiftUI의 여느 뷰와 똑같이 사용해 주면 된다.
struct UIVIewRepresentablePracticeView: View {
var body: some View{
VStack {
UIKitTextField()
.frame(height : 40)
}
}
}
# 🥨 TextField에 clear button 생성하기
SwiftUI를 활용해서도 textField 뒤에 붙어 있는 clear button을 만들어줄 수 있겠지만, UIKit를 이용하면 코드적으로 좀 더 직관적이게 TextField에 clearButton을 붙여줄 수 있을 것 같아서 예시로 구현해 보았다.
SwiftUI로 TextField에 clear button 생성할 수 있는 방법은 다양하다.
방법 1)
struct UIVIewRepresentablePracticeView: View {
@State var bindingString : String = ""
func TextFieldUIKit(text: Binding<String>) -> some View{
UITextField.appearance().clearButtonMode = .whileEditing
return TextField("입력", text: text)
}
var body: some View {
VStack {
TextFieldUIKit(text: self.$bindingString)
}
}
}
방법 2)
struct UIVIewRepresentablePracticeView: View {
@State var bindingString : String = ""
var body: some View {
VStack {
TextField("NAME", text: $bindingString)
.modifier(ClearButton(text: $bindingString))
}
}
}
public struct ClearButton: ViewModifier {
@Binding var text: String
public init(text: Binding<String>) {
self._text = text
}
public func body(content: Content) -> some View {
HStack {
content
Spacer()
Image(systemName: "multiply.circle.fill")
.foregroundColor(.secondary)
.opacity(text == "" ? 0 : 1)
.onTapGesture { self.text = "" }
}
}
}
UIViewRepresentable 사용해서 UIKit으로 UITextField에 clearButton 생성
방법 1)
UITextField의 appearance()메서드를 사용해서 텍스트필드에 글자를 입력 중일 때 clear button이 나올 수 있도록 설정해준다,
struct UIKitTextField : UIViewRepresentable {
private let textField = UITextField()
func makeUIView(context: UIViewRepresentableContext<UIKitTextField>) -> UITextField{
//textField의 style
textField.backgroundColor = .gray
textField.layer.cornerRadius = 3
UITextField.appearance().clearButtonMode = .whileEditing
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<UIKitTextField>){
print("updateUIView")
}
}
방법 2)
UIButton을 따로 생성해주고 textField.rightView를 사용해서 버튼을 넣어주는 방법이 있다. 이는 보통 해당 버튼을 눌렀을 때 추가적인 특정 동작을 원할 때 사용할 수 있으며, #selector를 만들어서 clearButton.addTarget 내부에 넘겨주면된다.
struct UIKitTextField : UIViewRepresentable {
private let textField = UITextField()
let helper : Helper = Helper()
class Helper {
public var onClickCancelButton: (() -> Void)?
@objc func clickCancelButton() {
onClickCancelButton?()
print("onClickClearButton")
}
}
func makeUIView(context: UIViewRepresentableContext<UIKitTextField>) -> UITextField{
//textField의 style
textField.backgroundColor = .gray
textField.layer.cornerRadius = 3
//textField 우측에 UIButton으로 clearButton 삽입
let btnImage = UIImage(systemName: "multiply")
let clearButton = UIButton(type: .custom)
clearButton.setImage(btnImage, for: .normal)
clearButton.tintColor = UIColor.lightGray
helper.onClickCancelButton = {
textField.text = ""
}
clearButton.addTarget(helper, action: #selector(helper.clickCancelButton), for: .touchUpInside)
textField.rightView = clearButton
textField.rightViewMode = .always
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<UIKitTextField>){
print("updateUIView")
}
}
TextField에 clear button을 넣어주는것을 예제로 기본적인 UIViewRepresentable 사용 방법을 알아보았다. 이것 외에도UIViewRepresentable을 사용할 때 SwiftUI -> UIKit 방향으로 데이터 전달하는 방법, UIKit -> SwiftUI 방향으로 데이터 전달하는 방법이 있다. 전자는 @Binding property를 활용하는 방법이고, 후자는 Coordinator를 활용하는 방법이다. 이렇게 데이터 방향에 대한 이해를 2편에서 알아 볼 것이다.
'SwiftUI' 카테고리의 다른 글
[SwiftUI] Custom Picker로 textField 입력값 받기 (0) | 2023.06.12 |
---|---|
SwiftUI에서 UIKit 사용하기 UIViewRepresentable(2) | @Binding 이란? Coordinator 란? (0) | 2023.06.09 |
SwiftUI 다양한 토글 형태를 만들어 주기 위한 ToggleStyle 프로토콜 (0) | 2023.06.06 |
SwiftUI 재사용가능한 뷰를 만들기 위해 필요한 @ViewBuilder (0) | 2023.06.05 |
SwiftUI 공통 스타일 주기 Custom View Modifier (0) | 2023.06.01 |