XZ_iOS implements textView placeholder text and placeholder image

According to the recent project requirements, there is a picture effect similar to the leftView of the label on the left side of the textView and can adapt to the height. Therefore, I customized a textView to achieve the effect, and improved it along the way, and realized the textView to set placeholder characters and modify it. Placeholder character color/font size, setting the maximum number of lines, setting rounded corners and other functions;

1. Realize the effect of the picture on the left

The effect diagram is as follows:


Implementation code:

/// Set the image
var hasImage: Bool? A
    didSet {
       if (hasImage != nil) && (hasImage == true) {
                
          addSubview(imageView)
          attributedText = imageText(font: UIFont.systemFont(ofSize: fontSize!))
        }
    }
}

/// Convert the current image to an image as attribute text
func imageText(font: UIFont) -> NSAttributedString {
    // 1. Determine if the image exists
    guard let image = image else {
        return NSAttributedString.init(string: "")
    }
        
    // 2. Create a text attachment
    let attchment = NSTextAttachment()

    attchment.image = image
    let height = font.lineHeight
    attchment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
        
    // 3. Return the image attribute text
    let attrStrM = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attchment))
        
    // set font properties
    attrStrM.addAttribute(NSAttributedStringKey.font, value: font, range: NSRange(location: 0, length: 1))
        
    // 4. Return the attribute text
    return attrStrM
}

2. Realize adaptive height

Implementation principle: listen for changes in the value of textView, and dynamically calculate the height, if the height is less than the initial value, use the initial value, otherwise use the calculated height  block callback to update the height of the textView

Implementation code:

    /// The value of textView changes
    @objc func textDidChanged () {

        // 1. Whether the placeholder text is hidden
        placeHolderView.isHidden = (text.lengthOfBytes(using: .utf8) > 0)
        
        // 2. Calculate the height
        var height = CGFloat(ceilf(Float(sizeThatFits(CGSize(width: bounds.size.width
            , height: CGFloat(MAXFLOAT))).height)))
        
        // 2.1 Set the minimum height: initial height
        height = (height < orginalHeight) ? orginalHeight : height
        
        // 3. Fit the height
        if textHeight != height {
            
            // Only fit the height, not limit the number of rows
            if maxHeight == CGFloat(MAXFLOAT) {
                isScrollEnabled = false
            }else {
                isScrollEnabled = ((height > maxHeight) && (maxHeight > 0))
            }
            
            textHeight = height
            
            if isScrollEnabled == false {
                
                blockHeightChanged?(text, height)
                
                superview?.layoutIfNeeded()
            }
        }
        
    }

3. Implement placeholder characters

The principle of placeholder characters is very simple. You can customize a UILabel property in a custom UITextView as the view of placeholder characters.

Show results:


Implementation code:

/// Create a placeholder view
 func placeholderView() {
        
    placeHolderView.frame = bounds
    placeHolderView.font = font
    placeHolderView.textColor = UIColor.lightGray
    placeHolderView.backgroundColor = UIColor.clear
    addSubview(placeHolderView)
}

 /// placeholder character
 var placeHolder: String? {
     didSet{
         if let _ = placeHolder {
            placeholderView()
            placeHolderView.text = placeHolder
         }
     }
 }

4. Modify the color/font size of placeholder characters

Implementation code:

    /// placeholder character color
    var placeholderColor: UIColor? {
        didSet{
            if let _ = placeHolder {
                placeHolderView.textColor = placeholderColor
            }
        }
    }

    /// placeholder character size
    var placeholderFontSize: CGFloat? {
        didSet{
            if let _ = placeHolder {
                placeHolderView.font = UIFont.systemFont(ofSize: placeholderFontSize ?? fontSize!)
            }
        }
    }

5. Set the maximum number of rows

It should be noted that if the maximum number of lines is set, before reaching the maximum number of lines, the scrolling of the textView needs to be turned off, that is, isScrollEnabled = false, otherwise during the writing process, the phenomenon of moving up and then falling back may occur.

Implementation code:

    /// If the number of lines is 0, just wrap
    var numOfLines: Int? {
        didSet {
            let font = UIFont.systemFont(ofSize: fontSize!)
            
            if numOfLines == 0 {
                maxHeight = CGFloat(MAXFLOAT)
                return
            }
            
            /// Maximum row height
            maxHeight = CGFloat(ceilf(Float(font.lineHeight * CGFloat(numOfLines ?? 6) + textContainerInset.top + textContainerInset.bottom)))
        }
    }

6. Set rounded corners

Implementation code:

    /// Set rounded corners
    var cornerRadius:CGFloat? {
        didSet {
            layer.cornerRadius = cornerRadius ?? 0.0
        }
    }

Finally, the demo address is attached , and you are welcome to point out mistakes.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325918475&siteId=291194637