Lilia
Lilia

Reputation: 512

Breaking line in custom text in SwiftUI

I need to have a long text that detects automatically the links in it, and if so, they would be clickable and in other color. I've succeed to do that. However, I have a problem going back to the line, this code returns all the text in one single line. I've tried adding "\n", fixedSize, layoutPriority but none of those worked.

struct RichTextView: UIViewRepresentable {
var text: String

func makeUIView(context: Context) -> UITextView {
    let textView = UITextView()
    textView.backgroundColor = .clear
    textView.isEditable = false
    textView.isScrollEnabled = false
    textView.font = UIFont.systemFont(ofSize: 18)
    textView.dataDetectorTypes = .all
    textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: Colors.colorPrimary()]
    textView.translatesAutoresizingMaskIntoConstraints = false
    textView.textContainer.lineBreakMode = .byWordWrapping
    textView.textContainer.widthTracksTextView = true
    return textView
}

func updateUIView(_ uiView: UITextView, context: Context) {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = 5  // Set line spacing
    paragraphStyle.paragraphSpacing = 10  // Set paragraph spacing
    paragraphStyle.lineBreakMode = .byWordWrapping
    paragraphStyle.lineBreakStrategy = NSParagraphStyle.LineBreakStrategy()

    let attributedString = NSAttributedString(
        string: text,
        attributes: [
            .font: UIFont.systemFont(ofSize: 18),
            .paragraphStyle: paragraphStyle
        ]
    )

    uiView.attributedText = attributedString
    uiView.sizeToFit()
    uiView.isScrollEnabled = false
}}

So this is my custom view that detects links , and this is how I call it

 RichTextView(text: description)
        .frame(width: UIScreen.screenWidth, height: viewHeight)
            .padding([.leading, .trailing])
            .padding(.bottom, 16)
            .multilineTextAlignment(.leading)
            .lineLimit(nil)
            .layoutPriority(1)
            .lineSpacing(8)
            .fixedSize(horizontal: false, vertical: false)
            .onAppear {
                self.viewHeight = calculateHeight(for: description, width: .infinity)
            }
            .onChange(of: description) { _ in
                self.viewHeight = calculateHeight(for: description, width: .infinity)
            }

I'm not sure that calculatedHeight is relevant but I'm going to put it anyways.

private func calculateHeight(for text: String, width: CGFloat) -> CGFloat {
let textView = UITextView()
textView.text = text
textView.font = UIFont.systemFont(ofSize: 18)  // Use default system font with size 18

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5  // Set line spacing
paragraphStyle.paragraphSpacing = 10  // Set paragraph spacing

let attributedString = NSAttributedString(
    string: text,
    attributes: [
        .font: UIFont.systemFont(ofSize: 18),
        .paragraphStyle: paragraphStyle
    ]
)
textView.attributedText = attributedString
    textView.textContainer.lineBreakMode = .byWordWrapping
    textView.textContainer.widthTracksTextView = true
textView.translatesAutoresizingMaskIntoConstraints = false
        textView.textContainer.maximumNumberOfLines = 0
let size = textView.sizeThatFits(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
return size.height}

Upvotes: 0

Views: 71

Answers (0)

Related Questions