1

I have a custom UITextView that shows a placeholder, like so:

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
        }
    }

}

I've put the UITextView inside a UIView which sits inside a UIStackView so that I can hide it and show it as needed. It's hidden by default. However, when run the app, the text view looks like this:

enter image description here

When it should look like this:

enter image description here

I've noticed on the storyboard that the width of the UIView is 64 when it's hidden inside the UIStackView and 428 when it's not hidden. So I think what might be happening is that the placeholder is setup when the UIView is 64, but isn't updated when the UIView is shown in the UIStackView.

What should I do to the UITextView extension so that it shows the placeholder in its full uncut length?

I've tried adding the following below addSubview(label), but it hasn't helped:

label.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: superview!.leadingAnchor, constant: 0).isActive = true
label.trailingAnchor.constraint(equalTo: superview!.trailingAnchor, constant: 0).isActive = true
label.topAnchor.constraint(equalTo: superview!.topAnchor, constant: 0).isActive = true
label.bottomAnchor.constraint(equalTo: superview!.bottomAnchor, constant: 0).isActive = true
user86516512
  • 445
  • 4
  • 13

1 Answers1

0

You have added addSubview(label) but not given it constraints. Could you try pinning its frame to the frame of the superview? Don't forget to set translatesAutoresizingMaskIntoConstraints to false

my3vshenoy
  • 51
  • 1
  • 4
  • I updated my question to include the code you asked me to try. Unfortunately it didn't seem to work, wondering if I'm doing something wrong. – user86516512 May 12 '21 at 01:21