LoginSignup
0
2

More than 5 years have passed since last update.

A content-wrapping, scrollable multiline UITextView with maximum size in Swift

Last updated at Posted at 2018-05-01

Conditions

Assume the following, common requirements:

  • A UITextView with text appears at center of screen
  • The textView height must adjust to fit the text height, but is scrollable if beyond a specified maximum height
  • The textView width must adjust to fit the text width, up to a maximum width
  • The textView must use center justified text if only one line, natural justified text other otherwise

Solution

  • Initialize the UITextView with the following properties
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = true
textView.showsVerticalScrollIndicator = true
textView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
  • Set the textView properties to multiline:
textView.numberOfLines = 0
textView.lineBreakMode = .byWordWrapping
  • Set vertical content compression on the textView, with a value which is less than the default 1000:
textView.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: UILayoutConstraintAxis.vertical)
  • Put the textView inside a custom container view, and constrain their edges to be equal

  • Set fixed constraints on the container width and height, so that they are no more than some fraction of a parent view size. These constraints will adopt the default priority of 1000, and are therefore prioritized ahead of constraints set by the textView content.

    NSLayoutConstraint(item: containerView,
                       attribute: .height,
                       relatedBy: .lessThanOrEqual,
                       toItem: parentView,
                       attribute: .height,
                       multiplier: containerSizeFraction, // e.g. 0.7
                       constant: 0.0),

  • Override "layoutSubviews" of the container view to perform the remainder of the fitting - it will be called when adding the the UITextView to the container view. We summarize the fitting with the following lines:

First, ensure the textView is always showing the top line when its layout is rearranged.


override func layoutSubviews() {
        super.layoutSubviews()

    textView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: false)

Then compute the textView size based its content

    let size = textView.sizeThatFits(CGSize(width: textView.contentSize.width, height: CGFloat.greatestFiniteMagnitude))

Constrain the textView width and height to size.width and size.height respectively. For each constraint, set the priority as:

    widthConstraint.priority = UILayoutPriority(rawValue: 750) }
    heightConstraint.priority = UILayoutPriority(rawValue: 750) }

Set the text alignment according to the current number of lines.

    textView.textAlignment = ( textView.contentSize.height >= font.lineHeight) ? .natural : .center
    textView.setNeedsDisplay()

It is helpful to briefly show the scroll indicator to highlight if the textView is now scrollable

    textView.flashScrollIndicators()
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2