iosswiftswiftuiuikit

How to force empty UITextView to be scrollable using a Swift UI view representable


For the purposes of an app I'm building I need a text editor that fills the phone screen, and is always scrollable.

Since I'd like some extra control over the formatting of text and scroll behaviour of the view, I've chosen to go for a UITextView wrapped in a UIViewRepresentable rather than the pretty basic TextEditor from SwiftUI.

Although the default scrolling behaviour I need is default on a TextEditor, it doesn't seem to happen at all in a UITextView, until I manually type out enough characters for the view to need it.

I've tried forcing some of the obvious variables and trying to set the frame of the UITextView, to no luck (with the latter seeming to do nothing at all).

How can I make a UITextView that mimics the always scrollable behaviour of the TextEditor?

import SwiftUI

struct SwiftUIView: View {
    var body: some View {
        VStack {
            TextView()
        }
    }
}

struct TextView: UIViewRepresentable {
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 100, height: 600)) // For example, doesn't seem to make any difference to the height

        textView.font = .systemFont(ofSize: 32, weight: .bold)

        textView.isScrollEnabled = true
        textView.isUserInteractionEnabled = true
        textView.showsVerticalScrollIndicator = true

        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {}
}

Solution

  • UITextView extends UIScrollView which has a few "bounce" related properties.

    Simply setting the alwaysBounceVertical property to true gives the behavior you are looking for. Add alwaysBounceHorizontal if desired.

    struct TextView: UIViewRepresentable {
        func makeUIView(context: Context) -> UITextView {
            let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 100, height: 600)) // For example, doesn't seem to make any difference to the height
    
            textView.font = .systemFont(ofSize: 32, weight: .bold)
    
            textView.alwaysBounceVertical = true // This adds vertical bounce
    
            return textView
        }
    
        func updateUIView(_ uiView: UITextView, context: Context) {}
    }