Note, that it must work with different number of lines in UILabel – 1,2,3 etc.
I’ve already found solution for 1 line label, where you mask UILabel’s layer with CAGradientLayer, but it doesn’t work for multiline labels, as it masks the whole layer and fades out all lines.
I tried to make another CALayer with position calculated to be in the position of last line with desired width and used CAGradientLayer as mask and add this layer as sublayer of UILabel, it worked for static objects, but i use this UILabel in UITableViewCell and when it’s tapped – it changes color to gray and i can see my layer, because it uses background color of UILabel when view layout its subviews, and also something wrong with x position calculation:
extension UILabel {
func fadeOutLastLineEnd() { //Call in layoutSubviews
guard bounds.width > 0 else { return }
lineBreakMode = .byCharWrapping
let tmpLayer = CALayer()
let gradientWidth: CGFloat = 32
let numberOfLines = CGFloat(numberOfLines)
tmpLayer.backgroundColor = UIColor.white.cgColor
tmpLayer.frame = CGRect(x: layer.frame.width - gradientWidth,
y: layer.frame.height / numberOfLines,
width: gradientWidth,
height: layer.frame.height / numberOfLines)
let tmpGrLayer = CAGradientLayer()
tmpGrLayer.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
tmpGrLayer.startPoint = CGPoint(x: 1, y: 0)
tmpGrLayer.endPoint = CGPoint(x: 0, y: 0)
tmpGrLayer.frame = tmpLayer.bounds
tmpLayer.mask = tmpGrLayer
layer.addSublayer(tmpLayer)
}
}
So, i need :
- which can be multiline
- end of last line needs to be faded out (gradient?)
- works in UITableViewCell, when the whole object changes color
2
Answers
You should create a
CATextLayer
with the same text properties as yourUILabel
.Fill it with the end of your text you wish to fade.
Then calculate the position of this text segment in your
UILabel
.Finally overlay the two.
Here are some aspect explained.
There are various ways to do this — here’s one approach.
We can mask a view by setting the
layer.mask
. The opaque areas of the mask will show-through, and the transparent areas will not.So, what we need is a custom layer subclass that will look like this:
This is an example that I’ll call
InvertedGradientLayer
:Next, we’ll make a
UILabel
subclass that implements thatInvertedGradientLayer
as a layer mask:and here is a sample view controller showing it in use:
When running, it looks like this:
The red dashed borders are there just so we can see the frames of the labels. Tapping the up/down arrows will increment/decrement the max number of lines to show in each label.