Swift3 圆圈内的文字UI3

Swift3 圆圈内的文字UI3,swift3,uilabel,textkit,Swift3,Uilabel,Textkit,我知道这已经被问了很多次了,所以我找不到一个可靠的答案在Swift或甚至是一个好的答案一般 我知道这在UITextField中是可能的,但UILabel是我想要使用的 我在问是否有人遇到过UILabel的扩展,它将文本包装在具有圆角的UILabel中。我创建了此UILabel。 有人觉得它有用吗 没那么好笑。我得到的印象是,讽刺和消极正在社区中蔓延。我最近看到的是,精英主义和对新成员或知识较少的成员的不良态度伪装成有用的建议。 import UIKit import CoreText @IBD

我知道这已经被问了很多次了,所以我找不到一个可靠的答案在Swift或甚至是一个好的答案一般

我知道这在UITextField中是可能的,但UILabel是我想要使用的


我在问是否有人遇到过UILabel的扩展,它将文本包装在具有圆角的UILabel中。

我创建了此UILabel。 有人觉得它有用吗


没那么好笑。我得到的印象是,讽刺和消极正在社区中蔓延。我最近看到的是,精英主义和对新成员或知识较少的成员的不良态度伪装成有用的建议。
import UIKit
import CoreText

@IBDesignable
open class ICRoundLabel: UILabel {

// Switch on/off text rounding, is on by default
@IBInspectable open dynamic var isRounded:Bool = true {
    didSet{
        setNeedsDisplay()
    }
}

// Specify text alignment
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'roundedTextAlignment' instead.")
@IBInspectable open dynamic var alignment:UInt8 {
    set{
        self.roundedTextAlignment = CTTextAlignment(rawValue: newValue)!
        setNeedsDisplay()
    }
    get{
        return roundedTextAlignment.rawValue
    }
}

// Font scale
@IBInspectable open dynamic var fillTextInCenter:Bool = true {
    didSet{
        setNeedsDisplay()
    }
}

// Font step
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'internalFontStep' instead.")
@IBInspectable open dynamic var fontStep:CGFloat {
    set(newValue) {
        internalFontStep = max(newValue, 0.1)
    }
    get {
        return internalFontStep
    }
}

open var roundedTextAlignment:CTTextAlignment = .center
open var internalFontStep:CGFloat = 1

override open func drawText(in rect: CGRect) {

    // Check if custom text draw is needed
    if !isRounded {
        super.drawText(in: rect)
        return
    }

    // Check if text exists
    guard let text = self.text else {
        return
    }

    if text == "" {
        return
    }

    // Get graphics context
    guard let context = UIGraphicsGetCurrentContext() else {
        return
    }

    //MARK: Create attributed string
    var stringRange = NSMakeRange(0, text.characters.count)
    let attrString = CFAttributedStringCreate(kCFAllocatorDefault, text as CFString!, attributedText?.attributes(at: 0, effectiveRange: &stringRange) as CFDictionary!)
    let attributedString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, CFIndex.max, attrString)!
    let stringLength = CFAttributedStringGetLength(attributedString)

    // Set a paragraph style
    let cfStringRange = CFRangeMake(0, stringLength)
    let settings = [CTParagraphStyleSetting(spec: .alignment, valueSize: MemoryLayout.size(ofValue: roundedTextAlignment), value: &roundedTextAlignment)]
    let paragraphStyle = CTParagraphStyleCreate(settings, 1)

    CFAttributedStringSetAttribute(attributedString, cfStringRange, kCTParagraphStyleAttributeName, paragraphStyle)

    // Make custom transitions with context
    context.translateBy(x: 0.0, y: frame.size.height)
    context.scaleBy(x: 1.0, y: -1.0)

    // New drawing rect with insets
    let drawingRect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: rect.size.width, height: rect.size.height))

    // Align text in center
    var boundingBox = text.boundingRect(with: drawingRect.size, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

    //MARK: Create elliptical path
    var path = CGPath(roundedRect: drawingRect, cornerWidth: drawingRect.width/2, cornerHeight: drawingRect.height/2, transform: nil)

    //MARK: Frame and range calculation nested function
    func getTextFrameRange() -> (CTFrame, CFRange) {
        let textFrame = CTFramesetterCreateFrame(CTFramesetterCreateWithAttributedString(attributedString), cfStringRange, path, nil)
        let rangeThatFits = CTFrameGetVisibleStringRange(textFrame)
        return (textFrame, rangeThatFits)
    }

    var textFrame:CTFrame
    var rangeThatFits:CFRange

    //MARK: Scaling font size if needed

    if fillTextInCenter {

        var fontSize = font.pointSize
        var estimatedFont = font.withSize(fontSize)

        // Pin text in center of initial rect
        var boxHeight = ceil(boundingBox.height)

        func updateBoundingBox() {
            boundingBox.origin = CGPoint(x: ceil((drawingRect.size.height - boxHeight)/2), y: ceil((drawingRect.size.height - boxHeight)/2))
            boundingBox.size = CGSize(width: boxHeight, height: boxHeight)
        }

        path = CGPath(roundedRect: boundingBox, cornerWidth: boundingBox.width/2, cornerHeight: boundingBox.height/2, transform: nil)

        (_, rangeThatFits) = getTextFrameRange()

        updateBoundingBox()

        // Fit text in center
        while cfStringRange.length != rangeThatFits.length {

            // Increase size of bounding box size if needed
            // or decrease font size
            if boundingBox.width < drawingRect.width {

                boxHeight += 1

                //Update bounding box accoringly to new box size
                updateBoundingBox()

                path = CGPath(roundedRect: boundingBox, cornerWidth: boundingBox.width/2, cornerHeight: boundingBox.height/2, transform: nil)

                (_, rangeThatFits) = getTextFrameRange()

                continue
            } else {

                CFAttributedStringSetAttribute(attributedString, cfStringRange, kCTFontAttributeName, estimatedFont)

                (_, rangeThatFits) = getTextFrameRange()

                // Increase or decrease font size
                fontSize += cfStringRange.length < rangeThatFits.length ? internalFontStep : -internalFontStep
                estimatedFont = font.withSize(fontSize)
            }
        }
    }

    //MARK: Draw the text frame in the view's graphics context
    (textFrame, _) = getTextFrameRange()
    CTFrameDraw(textFrame, context)

}

@IBInspectable var borderColor: UIColor = UIColor.white {
    didSet {
        layer.borderColor = borderColor.cgColor
    }
}

@IBInspectable var borderWidth: CGFloat = 1.0 {
    didSet {
        layer.borderWidth = borderWidth
    }
}

override open func layoutSubviews() {
    super.layoutSubviews()
    layer.cornerRadius = 0.5 * bounds.size.width
    clipsToBounds = true


}
}