UIViewRepresentable이란 SwiftUI에서 UIKit을 사용할 수 있도록 해주는 것
UIViewRepresentable 이란
SwiftUI를 사용하다보면 UIKit을 사용할 때가 있고 UIKit을 SwiftUI로 바꿔야하는 경우가 발생할 수 있습니다. 이때 사용할 수 있는 것이 바로 UIViewRepresentable입니다.
UIViewRepresentable 구성
기본적인 메서드는 makeUIView와 updateUIView가 존재합니다.
makeUIView 란
makeUIView는 UIKit의 UIView를 만들고 싶을 때 해당 뷰를 makeUIView 내부에 구현한 후 View에 넣어서 적용합니다.
struct BasicUIViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
간단한 makeUIView 적용 코드 & 화면
makeUIView를 사용하여 만든 UIView는 SwiftUI의 View에 넣어 사용할 수 있게 됩니다.
struct ContentView: View {
var body: some View {
VStack {
Text("hello world")
BasicUIViewRepresentable()
}
}
}
#Preview {
ContentView()
}
struct BasicUIViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
let view = UIView()
view.backgroundColor = .red
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
UIKit을 SwiftUI에서 사용해야하는 이유
이유는 여러가지로 설명할 수 있지만 간단히 얘기하면 UIKit은 SwiftUI가 만들어진지 오래전부터 사용됐던 언어로 SwiftUI에서 다룰 수 없는 여러가지 기능을 사용할 수 있습니다.
예를 들어 현재는 prompt를 제공하게 되어 해결됐지만 SwiftUI에서는 TextField의 placeholder의 색깔을 바꿀 수 없는 것처럼 제한되는 문제들이 있었습니다. UIKit에서는 이런 기능들을 예전부터 제공해왔기에 이런 기능들을 사용할 수 있게끔 만들어주는 것 입니다.
UIKit에서 UITextField 만들기
UIKit에서 UITextField를 만드는 방법은 다음과 같습니다. SwiftUI의 TextField는 UITextField로 만들고 placeholder의 스타일을 attributedPlaceholder를 사용하여 .foregroundColor를 파란색으로 설정하게 되면 파란색 placeholder로 바뀌게 됩니다.
struct UITextFieldViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
getTextField()
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
private func getTextField() -> UITextField {
let textfield = UITextField(frame: .zero)
let placeholder = NSAttributedString(
string: "입력...",
attributes: [
.foregroundColor : UIColor.blue
])
textfield.attributedPlaceholder = placeholder
return textfield
}
}
UIKit으로 만든 TextField의 입력값을 SwiftUI에서 사용하기
UITextField의 입력값을 SwiftUI에서 업데이트 받기 위해서는 makeCoordinator를 먼저 이해해야합니다.
makeCoordinator란 UIView에서 발생하는 변화를 다른 SwiftUI 인터페이스에 전달하기 위해 만드는 커스텀 인스턴스입니다.
UITextField 에서 입력값의 변화를 인지하기 위해서는 delegate 대리자를 위임해야합니다. delegate란 변화에 대해서 대신 처리해주는 역할을 하는 것이라고 생각하면 됩니다. 그러기 위해서 delegate를 만들어줘야 합니다.
class TextFieldDelegate: NSObject, UITextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
self._text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
그리고 만든 UITextFieldDelegate 클래스를 makeCoordinator()를 사용하여 UIView에서 발생하는 변화를 인식해서 SwiftUI 인터페이스에 변화를 전달합니다.
func makeCoordinator() -> TextFieldDelegate {
return TextFieldDelegate(text: $text)
}
또한 makeUIView에서 만든 UITextField의 delegate를 context.coordinator를 통해 설정하였습니다.
func makeUIView(context: Context) -> some UIView {
let textfield = getTextField()
textfield.delegate = context.coordinator
return textfield
}
위의 makeUIView를 다음과 같이 UITextField를 반환하도록 만들수도 있습니다. 왜냐면 UITextField는 UIView에 상속되어 있기 때문입니다.
func makeUIView(context: Context) -> UITextField {
let textfield = getTextField()
textfield.delegate = context.coordinator
return textfield
}
마지막으로 SwiftUI에서 변화하는 내용을 UIKit에서 업데이트하는 방법으로 updateUIView를 사용하는 것 입니다.
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
}
아래는 UITextField를 만드는 전체 코드입니다.
struct UITextFieldViewRepresentable: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textfield = getTextField()
textfield.delegate = context.coordinator
return textfield
}
// SwiftUI에서 UIKit로 변화 업데이트
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
}
private func getTextField() -> UITextField {
let textfield = UITextField(frame: .zero)
let placeholder = NSAttributedString(
string: "입력...",
attributes: [
.foregroundColor : UIColor.blue
])
textfield.attributedPlaceholder = placeholder
return textfield
}
// UIKit에서 SwiftUI로 변화 업데이트
func makeCoordinator() -> TextFieldDelegate {
return TextFieldDelegate(text: $text)
}
class TextFieldDelegate: NSObject, UITextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
self._text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
}
동적으로 만들기
추가로 동적으로 만들 수 있습니다.
UITextFieldViewRepresentable(text: $text)
.updatePlaceholder("New placeholder")
.frame(height: 55)
.background(Color.gray)
struct UITextFieldViewRepresentable: UIViewRepresentable {
@Binding var text: String
let placeholder: String
let placeholderColor: UIColor
init(text: Binding<String>, placeholder: String, placeholderColor: UIColor = .red) {
self._text = text
self.placeholder = placeholder
self.placeholderColor = placeholderColor
}
func updatePlaceholder(_ text: String) -> UITextFieldViewRepresentable {
var viewRepresentable = self
viewRepresentable.placeholder = text
return viewRepresentable
}
'SwiftUI' 카테고리의 다른 글
UIViewControllerRepresentable (0) | 2024.04.27 |
---|---|
PreferenceKey (0) | 2024.04.25 |
사용자한테 보여줄 색깔 선택하기 (0) | 2024.04.23 |
Custom tab bar (0) | 2024.04.22 |
aligmentGuide (0) | 2024.04.21 |