Я использую UITextView через UIViewRepresentable, потому что TextEditor не обеспечивает надежную автоматическую прокрутку при перетаскивании маркеров выделения текста вверх или вниз по длинному тексту.
Проблема заключается в визуальном обрезке рядом с полосами: текст сильно обрезается сверху и снизу при прокрутке.
Мне нужно такое же плавное/мягкое поведение краев, как у Apple Примечания.
Ожидаемое поведение:
- плавный переход между верхней и нижней полосами (без жесткого вырезания)
- горизонтальные вставки текста около 20 пт.
- полоса прокрутки по умолчанию остается в почти правом положении по умолчанию.
- автопрокрутка при перетаскивании продолжает работать
- contentInsetAdjustmentBehavior = .automatic
- удален вручную contentInset
- только textContainerInset для горизонтальных заполнение текста
- Настройки панели инструментов SwiftUI:
.toolbarBackgroundVisibility(.automatic, for: .navigationBar, .bottomBar) - .scrollEdgeEffectStyle(.soft, for: [.top, .bottom])
Я подозреваю, что это связано со смешиванием UIViewRepresentable(UITextView) с эффектами прокрутки края панели инструментов SwiftUI.
Минимальный пример:
Код: Выделить всё
import SwiftUI
import UIKit
struct NoteEditorView: View {
@State private var text = "Long text..."
@FocusState private var isFocused: Bool
var body: some View {
NativeTextView(text: $text, isFocused: $isFocused, textInset: 20)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button {} label: { Image(systemName: "square.and.arrow.up") }
Button {} label: { Image(systemName: "ellipsis") }
}
ToolbarItem(placement: .bottomBar) {
HStack {
Button {} label: { Image(systemName: "checklist") }
Button {} label: { Image(systemName: "paperclip") }
Button {} label: { Image(systemName: "pencil.tip.crop.circle") }
}
}
}
.toolbarBackgroundVisibility(.automatic, for: .navigationBar, .bottomBar)
.scrollEdgeEffectStyle(.soft, for: [.top, .bottom])
}
}
struct NativeTextView: UIViewRepresentable {
@Binding var text: String
var isFocused: FocusState.Binding
let textInset: CGFloat
func makeUIView(context: Context) -> UITextView {
let tv = UITextView()
tv.delegate = context.coordinator
tv.backgroundColor = .clear
tv.isScrollEnabled = true
tv.alwaysBounceVertical = true
tv.keyboardDismissMode = .interactive
tv.contentInsetAdjustmentBehavior = .automatic
tv.font = .preferredFont(forTextStyle: .body)
tv.textContainer.lineFragmentPadding = 0
tv.textContainerInset = UIEdgeInsets(top: 8, left: textInset, bottom: 16, right: textInset)
tv.text = text
return tv
}
func updateUIView(_ uiView: UITextView, context: Context) {
if uiView.text != text { uiView.text = text }
if isFocused.wrappedValue, !uiView.isFirstResponder {
uiView.becomeFirstResponder()
} else if !isFocused.wrappedValue, uiView.isFirstResponder {
uiView.resignFirstResponder()
}
}
func makeCoordinator() -> Coordinator { Coordinator(self) }
final class Coordinator: NSObject, UITextViewDelegate {
var parent: NativeTextView
init(_ parent: NativeTextView) { self.parent = parent }
func textViewDidChange(_ textView: UITextView) {
parent.text = textView.text
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... rolling-wa
Мобильная версия