UILabel with color gradient to certain height of the label

為{幸葍}努か 提交于 2019-12-08 03:28:35

问题


I want to achieve the effect from the picture bellow - a UILabel that shows progress X as a gradient from bottom to X% of height of the label. The remaining (100 - X)% of the label will have a different color.

The only thing that comes into my mind right now is to create two UIViews one with gray background and one with the color of the gradient. Put the gradient view above the gray view and set it’s height to match the current progress. Then simply use the label as a mask for those two views. For better illustration I attached a picture describing my suggested solution. Though I’m not happy with it because it is not very elegant.



Is it possible to achieve this in a different and more elegant way? Ideally just by subclassing UILabel.


回答1:


You could do this with layers and masks, but it will actually be easier to just set the text color with a UIColor from pattern image. This code works, though it might be better to subclass UILabel and give the class a method to apply and or update the image. I say this is easier, because I find dealing with text layers a bit of a pain to get the sizing perfect, where as labels can alter their font size with adjustsFontSizeToFitWidth.

 override func viewDidLayoutSubviews() {
    label.textColor = UIColor(patternImage: partialGradient(forViewSize: label.frame.size, proportion: 0.65))
}

func partialGradient(forViewSize size: CGSize, proportion p: CGFloat) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(size, false, 0)

    let context = UIGraphicsGetCurrentContext()


    context?.setFillColor(UIColor.darkGray.cgColor)
    context?.fill(CGRect(origin: .zero, size: size))

    let c1 = UIColor.orange.cgColor
    let c2 = UIColor.red.cgColor

    let top = CGPoint(x: 0, y: size.height * (1.0 - p))
    let bottom = CGPoint(x: 0, y: size.height)

    let colorspace = CGColorSpaceCreateDeviceRGB()

    if let gradient = CGGradient(colorsSpace: colorspace, colors: [c1, c2] as CFArray, locations: [0.0, 1.0]){
        // change 0.0 above to 1-p if you want the top of the gradient orange
        context?.drawLinearGradient(gradient, start: top, end: bottom, options: CGGradientDrawingOptions.drawsAfterEndLocation)
    }


    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img!
}




回答2:


You can use Core Animation with CATextLayer and CAGradientLayer.

import PlaygroundSupport

let bgView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
bgView.backgroundColor = UIColor.black
PlaygroundPage.current.liveView = bgView

let textLayer = CATextLayer()
textLayer.frame = bgView.frame
textLayer.string = "70"
textLayer.fontSize = 60

let gradientLayer = CAGradientLayer()
gradientLayer.frame = bgView.frame
gradientLayer.colors = [
    UIColor.gray.cgColor,
    UIColor(red: 1, green: 122.0/255.0, blue: 0, alpha: 1).cgColor,
    UIColor(red: 249.0/255.0, green: 1, blue: 0, alpha: 1).cgColor
]

//Here you can adjust the filling
gradientLayer.locations = [0.5, 0.51, 1]

gradientLayer.mask = textLayer
bgView.layer.addSublayer(gradientLayer)




回答3:


You can subclass UILabel and draw what you want in draw(_ rect: CGRect) function. Or if you want to do it fast you can subclass too and add gradient subview. Don't forget to resize it in layoutSubviews() function.



来源:https://stackoverflow.com/questions/41313125/uilabel-with-color-gradient-to-certain-height-of-the-label

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!