TextView placeholder being cut off when hidden inside StackView

Viewed 173

I have a TextView that I have placed inside a UIView, which is then placed inside a StackView, like so:

- UIStackView
    - UIView
        - UITextView

I also looked up a custom extension for UITextView which allows me to add a placeholder in the text view:

import UIKit

extension UITextView {

    private class PlaceholderLabel: UILabel { }

    private var placeholderLabel: PlaceholderLabel {
        if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
            return label
        } else {
            let label = PlaceholderLabel(frame: .zero)
            label.font = font
            addSubview(label)
            
            return label
        }
    }

    @IBInspectable
    var placeholder: String {
        get {
            return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
        }
        set {
            let placeholderLabel = self.placeholderLabel
            placeholderLabel.text = newValue
            placeholderLabel.numberOfLines = 0
            let width = frame.width - textContainer.lineFragmentPadding * 2
            let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
            placeholderLabel.frame.size.height = size.height
            placeholderLabel.frame.size.width = width
            placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)

            textStorage.delegate = self
        }
    }
    
    @IBInspectable
    var placeholderColor: UIColor? {
        get {
            self.placeholderColor
        }
        
        set {
            placeholderLabel.textColor = newValue
        }
    }

}

extension UITextView: NSTextStorageDelegate {

    public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
        if editedMask.contains(.editedCharacters) {
            placeholderLabel.isHidden = !text.isEmpty
        }
    }

}

However, when I set the UIView to be hidden inside the stack view, the placeholder is cut off after the UIView is made visible:

enter image description here

If I don't set the UIView to be hidden, it shows fine:

enter image description here

I found out that the width of the UIView inside the stack view changes when I set it to hidden:

enter image description here

As you can see, it's no longer full-width when hidden. Same with the UITextView:

enter image description here

My suspicion is that the placeholder text's constraints aren't being reset properly when the UIView is shown.

What should I do to fix this?

1 Answers

It seems like -

  1. even though the UIStackView is doing the correct thing by making the UIView.width/height == 0 when you mark it .isHidden = true
  2. contents inside this UIView are still visible outside it's bounds.

You could try setting clipsToBounds = true for your UIView that holds the UITextView.

- UIStackView
    - UIView ///// Try setting `clipsToBounds = true` for this one
        - UITextView
Related