Как использовать NSAttributedString с ScrollView в SwiftUI? - PullRequest
2 голосов
/ 24 января 2020

Я смог отрендерить NSAttributedString s с помощью UIViewRepresentable, который прекрасно работает, пока я не оберну вид в ScrollView.

При помещении внутрь ScrollView представление NSAttributedString останавливает рендеринг.

Я пробовал некоторые другие методы, которые заменяют NSAttributedString с добавлением нескольких представлений Text() вместе в получить форматирование, которое работает внутри ScrollView и поддерживает курсив и monospace font. К сожалению, это не работает для ссылок внутри текстовых блоков, что означает, что мне все еще нужно NSAttributedString.

import SwiftUI

struct TextWithAttributedString: UIViewRepresentable {

    var attributedString: NSAttributedString

    init(_ attributedString: NSAttributedString) {
        self.attributedString = attributedString
    }

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView(frame: .zero)
        textView.attributedText = self.attributedString
        textView.isEditable = false
        return textView
    }

    func updateUIView(_ textView: UITextView, context: Context) {
        textView.attributedText = self.attributedString
    }
}


let exampleText = """
Fugiat id blanditiis et est culpa voluptas. Vivamus aliquet enim eu blandit blandit. Sit eget praesentium maxime sit molestiae et alias aut.
"""

struct NSAttributedStringView: View {
    var body: some View {
// Note: when uncommented, the view breaks
//    ScrollView {
        TextWithAttributedString(NSAttributedString(string: exampleText))
//    }
    }
}

struct NSAttributedStringView_Previews: PreviewProvider {
    static var previews: some View {
        NSAttributedStringView()
            .previewLayout(.sizeThatFits)
    }
}

Редактировать: Я пытался использовать обернутый UITextView со свойством text, установленным вместо свойства attributeText, но это также не удается отобразить в ScrollView, поэтому проблема, похоже, заключается в UITextView, а не NSAttributedString.

Итак, вопрос в том, как заставить UITextView работать в ScrollView?

Ответы [ 2 ]

1 голос
/ 24 января 2020

Причина в том, что SwiftUI ScrollView требует определенного размера контента, но используется UITextView сам по себе UIScrollView и обнаруживает контент на основе доступного пространства в родительском представлении. Так происходит цикл неопределенных размеров.

Вот упрощенная демонстрация возможного подхода к решению этой проблемы. Идея состоит в том, чтобы рассчитать размер контента UITextView и передать его SwiftUI ...

struct TextWithAttributedString: UIViewRepresentable {
    @Binding var height: CGFloat
    var attributedString: NSAttributedString

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView(frame: .zero)
        textView.isEditable = false
        return textView
    }

    func updateUIView(_ textView: UITextView, context: Context) {
        textView.attributedText = self.attributedString

        // calculate height based on main screen, but this might be 
        // improved for more generic cases
        height = textView.sizeThatFits(UIScreen.main.bounds.size).height
    }
}


struct NSAttributedStringView: View {
    @State private var textHeight: CGFloat = .zero
    var body: some View {
        ScrollView {
            TextWithAttributedString(height: $textHeight, attributedString: NSAttributedString(string: exampleText))
                .frame(height: textHeight) // << specify height explicitly !
        }
    }
}
0 голосов
/ 09 апреля 2020

Если вы хотите использовать Asperi's TextWithAttributedString в качестве дочернего представления, замените

height = textView.sizeThatFits(UIScreen.main.bounds.size).height

на

DispatchQueue.main.async {
    height = textView.sizeThatFits(textView.visibleSize).height
}
...