XZ_iOS之实现textView占位文本和占位图片

最近项目需求,实现 textView 左侧有一个类似于 label 的 leftView 的图片效果 且 能自适应高度,所以,自定义了一个 textView 实现了效果,顺带着完善了一下,实现了 textView 设置占位字符,修改占位字符颜色/字体大小,设置最大行数、设置圆角等功能;

1、实现左侧图片的效果

效果图如下:


实现代码:

/// 设置图片
var hasImage:Bool? {
    didSet {
       if (hasImage != nil) && (hasImage == true) {
                
          addSubview(imageView)
          attributedText = imageText(font: UIFont.systemFont(ofSize: fontSize!))
        }
    }
}

/// 将当前的图像转换成图片为属性文本
func imageText(font: UIFont) -> NSAttributedString {
    // 1.判断图像是否存在
    guard let image = image else {
        return NSAttributedString.init(string: "")
    }
        
    // 2.创建文本附件
    let attchment = NSTextAttachment()

    attchment.image = image
    let height = font.lineHeight
    attchment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
        
    // 3.返回图片属性文本
    let attrStrM = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attchment))
        
    // 设置字体属性
    attrStrM.addAttribute(NSAttributedStringKey.font, value: font, range: NSRange(location: 0, length: 1))
        
    // 4.返回属性文本
    return attrStrM
}

2、实现自适应高度

实现原理:监听 textView 的值的改变,并动态计算高度,如果高度小于初始值,使用初始值,否则使用计算的高度 block 回调更新 textView 的高度

实现代码:

    /// textView 的值改变
    @objc func textDidChanged() {

        // 1.占位文字是否隐藏
        placeHolderView.isHidden = (text.lengthOfBytes(using: .utf8) > 0)
        
        // 2.计算高度
        var height = CGFloat(ceilf(Float(sizeThatFits(CGSize(width: bounds.size.width
            , height: CGFloat(MAXFLOAT))).height)))
        
        // 2.1 设置最小高度: 初始高度
        height = (height < orginalHeight) ? orginalHeight : height
        
        // 3.适配高度
        if textHeight != height {
            
            // 仅适配高度,不限制行数
            if maxHeight == CGFloat(MAXFLOAT) {
                isScrollEnabled = false
            }else {
                isScrollEnabled = ((height > maxHeight) && (maxHeight > 0))
            }
            
            textHeight = height
            
            if isScrollEnabled == false {
                
                blockHeightChanged?(text, height)
                
                superview?.layoutIfNeeded()
            }
        }
        
    }

3、实现占位字符

占位字符的原理很简单,在自定义的 UITextView 中自定义一个 UILabel的属性作为占位字符的视图即可

效果展示:


实现代码:

 /// 创建占位视图
 func placeholderView() {
        
    placeHolderView.frame = bounds
    placeHolderView.font = font
    placeHolderView.textColor = UIColor.lightGray
    placeHolderView.backgroundColor = UIColor.clear
    addSubview(placeHolderView)
}

 /// 占位字符
 var placeHolder: String? {
     didSet{
         if let _ = placeHolder {
            placeholderView()
            placeHolderView.text = placeHolder
         }
     }
 }

4、修改占位字符颜色/字体大小

实现代码:

    /// 占位字符颜色
    var placeholderColor: UIColor? {
        didSet{
            if let _ = placeHolder {
                placeHolderView.textColor = placeholderColor
            }
        }
    }

    /// 占位字符大小
    var placeholderFontSize: CGFloat? {
        didSet{
            if let _ = placeHolder {
                placeHolderView.font = UIFont.systemFont(ofSize: placeholderFontSize ?? fontSize!)
            }
        }
    }

5、设置最大行数

需要注意的是,如果设置了最大行数,在到达最大行数之前,需要将 textView 的滚动关闭,即 isScrollEnabled = false,否则在写的过程中,可能会出现上移然后回落的现象

实现代码:

    /// 行数 如果是0,只换行
    var numOfLines: Int? {
        didSet {
            let font = UIFont.systemFont(ofSize: fontSize!)
            
            if numOfLines == 0 {
                maxHeight = CGFloat(MAXFLOAT)
                return
            }
            
            /// 最大行高
            maxHeight = CGFloat(ceilf(Float(font.lineHeight * CGFloat(numOfLines ?? 6) + textContainerInset.top + textContainerInset.bottom)))
        }
    }

6、设置圆角

实现代码:

    /// 设置圆角
    var cornerRadius:CGFloat? {
        didSet {
            layer.cornerRadius = cornerRadius ?? 0.0
        }
    }

最后附上demo地址,欢迎大家指错。

猜你喜欢

转载自blog.csdn.net/understand_xz/article/details/79238495