每行文字下方画线的 UITextView

每行文字下方画线的 UITextView, 如下图:


屏幕快照 2018-12-06 下午9.20.37.png
import UIKit

@IBDesignable
public class LinedTextView: UITextView {
    @IBInspectable public var separatorLineHeight: CGFloat = 1
    @IBInspectable public var separatorLineColor: UIColor = UIColor.gray
    
    // should be called after setting all font attributes
    public func getRealHeight(numberOfLine: Int) -> CGFloat {
        guard let realLineHeight = realLineHeight, numberOfLine >= 0 else {
            return 0
        }
        return realLineHeight * CGFloat(numberOfLine) + textContainerInset.top + textContainerInset.bottom + separatorLineHeight / 2
    }
    
    public var realLineHeight: CGFloat? {
        guard let currentFont = font else {
            return nil
        }
        var lineHeight: CGFloat = currentFont.lineHeight
        var range: NSRange = NSRange(location: 0, length: text.lengthOfBytes(using: .unicode))
        if let paragraphStyle = attributedText.attribute(NSAttributedStringKey.paragraphStyle, at: 0, effectiveRange: &range) as? NSParagraphStyle {
            // priority order: maximumLineHeight > minimumLineHeight > lineHeightMultiple
            if paragraphStyle.lineHeightMultiple != 0 {
                lineHeight = paragraphStyle.lineHeightMultiple * currentFont.lineHeight
            }
            if paragraphStyle.minimumLineHeight != 0 {
                lineHeight = max(lineHeight, paragraphStyle.minimumLineHeight)
            }
            if paragraphStyle.maximumLineHeight != 0 {
                lineHeight = min(lineHeight, paragraphStyle.maximumLineHeight)
            }
        }
        return lineHeight
    }
    
    override public func draw(_ rect: CGRect) {
        super.draw(rect)
        guard let context = UIGraphicsGetCurrentContext(), let realLineHeight = realLineHeight, realLineHeight > 0 else {
            return
        }
        let firstVisibleLine: Int = max(1, Int(contentOffset.y / realLineHeight))
        let lastVisibleLine: Int = Int(ceil((contentOffset.y + bounds.size.height) / realLineHeight))
        guard firstVisibleLine < lastVisibleLine else {
            return
        }
        
        context.setLineWidth(separatorLineHeight)
        context.setStrokeColor(separatorLineColor.cgColor)
        context.beginPath()
        let startPointX: CGFloat = bounds.origin.x + textContainer.lineFragmentPadding + textContainerInset.left
        let endPointX: CGFloat = bounds.size.width - textContainer.lineFragmentPadding - textContainerInset.right

        for lineIndex in firstVisibleLine ..< lastVisibleLine {
            let linePointY: CGFloat = textContainerInset.top + realLineHeight * CGFloat(lineIndex)
            context.move(to: CGPoint(x: startPointX, y: linePointY))
            context.addLine(to: CGPoint(x: endPointX, y: linePointY))
        }
        
        context.closePath()
        context.strokePath()
    }
    
    // adjust position of cursor
    override public func caretRect(for position: UITextPosition) -> CGRect {
        guard let lineHeight = font?.lineHeight, let realLineHeight = realLineHeight, realLineHeight > 0 else {
            return super.caretRect(for: position)
        }
        var rect = super.caretRect(for: position)
        rect.origin.y = rect.origin.y + (realLineHeight - lineHeight)
        rect.size.height = lineHeight
        return rect
    }
}

参考:https://www.jianshu.com/p/a80b5bd9f307

你可能感兴趣的:(每行文字下方画线的 UITextView)