Если я хочу не прокручиваемый UITextView
, который принимает всю ширину, растёт и сжимается по вертикали, чтобы соответствовать его тексту, я могу сделать это так в UIKit:
import UIKit
class TestViewController: UIViewController {
private lazy var textView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
guard let view = view else { return }
view.backgroundColor = .white
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.backgroundColor = .systemYellow
textView.isEditable = true
textView.isSelectable = true
textView.isScrollEnabled = false // We want the view to resize to fit text instead of scrolling
view.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
]
NSLayoutConstraint.activate(constraints)
}
}
И это выглядит так this:
Я хочу связать это с SwiftUI, заключив UITextView
в UIViewRepresentable
. Я сделал это так, настроив представление текста точно так же, как в примере UIKit:
import SwiftUI
import UIKit
struct TextView: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.delegate = context.coordinator
textView.backgroundColor = .clear
textView.isEditable = true
textView.isSelectable = true
textView.isScrollEnabled = false // We want the view to resize to fit text instead of scrolling
// Makes the text wrap rather than extend on one line outside the parent frame
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return textView
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: _text)
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
}
}
extension TextView {
class Coordinator: NSObject, UITextViewDelegate {
@Binding var text: String
init(text: Binding<String>) {
self._text = text
}
func textViewDidChange(_ textView: UITextView) {
self.text = textView.text
}
}
}
И использовал его в SwiftUI так:
import SwiftUI
struct ContentView: View {
@State var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
var body: some View {
VStack(alignment: .leading) {
TextView(text: $text)
.background(Color.yellow)
Spacer()
}
}
}
Настройка textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
успешно заставляет текстовое представление переносить текст на несколько строк, но высота заполняет весь экран:
Добавление textView.setContentHuggingPriority(.defaultHigh, for: .vertical)
действительно уменьшает высоту, но теперь перенос строк больше не работает; весь текст в одной строке, которая выходит за рамки:
Я не нашел слишком много в документации или онлайн о том, как UIViewRepresentable
разметка мостов от UIKit до SwiftUI. Есть ли какой-нибудь способ добиться того, чтобы этот автомат c рос и уменьшался в зависимости от поведения? Или мне придется делать какие-то хакерские вещи с sizeThatFits
и устанавливать рамку вручную при каждом изменении текста?