codewithfeeling
codewithfeeling

Reputation: 6576

SwiftUI - How can I get multiline text to wrap in a UITextView without scrolling?

I am using the UIViewRepresentable wrapper to create a bindable multiline UITextVIew since there is still no multiline support for the native SwiftUI TextField. It all works fine as long as isScrollEnabled = true is set on the UITextView.

Is there a way to get the text to wrap without the UITextView being scrollable?

import SwiftUI

struct TextfieldIssue: View {
  @State var text: String = "Hello, I am some long text that will wrap if isScrollEnabled is set to true, but not if isScrollEnabled is set to false"

  var body: some View {
    MultilineTextField(text: $text)
  }
}

struct MultilineTextField: UIViewRepresentable {

  private let view = UITextView()

  @Binding var text: String

  func makeUIView(context: UIViewRepresentableContext<MultilineTextField>) -> UITextView {

    view.isEditable = true
    view.font = UIFont.systemFont(ofSize: 24)

    // Text wraps fine as long as this is true
    view.isScrollEnabled = true

    // Text does not wrap if this is uncommented
//    view.isScrollEnabled = false

    view.text = text
    view.delegate = context.coordinator

    return view
  }

  func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<MultilineTextField>) {
    uiView.text = text
  }

  func makeCoordinator() -> TextFieldCoordinator {
    let coordinator = TextFieldCoordinator(self)
    self.view.delegate = coordinator

    return coordinator
  }
}

class TextFieldCoordinator : NSObject, UITextViewDelegate {

  var parent: MultilineTextField

  init(_ multilineTextField: MultilineTextField) {
    self.parent = multilineTextField
  }

  func textViewDidChange(_ textView: UITextView) {
    self.parent.text = textView.text
  }
}

struct TextfieldIssue_Previews: PreviewProvider {
    static var previews: some View {
        TextfieldIssue()
    }
}

Upvotes: 2

Views: 2511

Answers (1)

codewithfeeling
codewithfeeling

Reputation: 6576

Just add this to makeUIView and the text will wrap.

view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

Here's the full updated makeUIView function:

func makeUIView(context: UIViewRepresentableContext<MultilineTextField>) -> UITextView {

    view.isEditable = true
    view.font = UIFont.systemFont(ofSize: 24)
    view.isScrollEnabled = false
    view.view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    view.delegate = context.coordinator
    view.text = text

    return view
  }

Upvotes: 11

Related Questions