Gradient BG in UICollectionViewCell - ios

I created a UICollectionView with cell like a credit cards and want to add gradient layer as a background of this cards. First I added background view for shadow(shadowView) and then add second view for gradient layer(bgView) and add CAGradientLayer as subLayer of bgView. But I didn't get any gradient view. This is my code:
class CardCell: BaseCell {
private var shadowView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.white
view.layer.shadowColor = UIColor.shadowColor.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 1.0)
view.layer.shadowOpacity = 0.1
view.layer.shadowRadius = 15.0
return view
}()
private var bgView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.backgroundColor = .clear
view.layer.addSublayer(createGradientLayer(for: view))
return view
}()
override func setup() {
super.setup()
addSubview(shadowView)
addSubview(bgView)
// setup constraints
shadowView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.9).isActive = true
shadowView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1).isActive = true
shadowView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
shadowView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
bgView.topAnchor.constraint(equalTo: shadowView.topAnchor).isActive = true
bgView.bottomAnchor.constraint(equalTo: shadowView.bottomAnchor).isActive = true
bgView.leadingAnchor.constraint(equalTo: shadowView.leadingAnchor).isActive = true
bgView.trailingAnchor.constraint(equalTo: shadowView.trailingAnchor).isActive = true
}
private static func createGradientLayer(for view: UIView) -> CAGradientLayer {
let color = UIColor(red:0.95, green:0.42, blue:0.64, alpha:1.0)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds
gradientLayer.colors = [color.cgColor, color.withAlphaComponent(0.7).cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.1, y: 1.1)
return gradientLayer
}
}
But If I change this code and remove gradient setting from bgView init and write it after constraints, everything is OK, BUT the shadow view go away:
. . .
bgView.leadingAnchor.constraint(equalTo: shadowView.leadingAnchor).isActive = true
bgView.trailingAnchor.constraint(equalTo: shadowView.trailingAnchor).isActive = true
bgView.layoutIfNeeded()
bgView.layer.addSublayer(CardCell.createGradientLayer(for: bgView))

extension UIView {
func addGradientToViewWithCornerRadiusAndShadow(radius:CGFloat,firstColor:UIColor,secondColor:UIColor,locations:[CGFloat]){
for layer in (self.layer.sublayers ?? []){
if let layer1 = layer as? CAGradientLayer{
layer1.removeFromSuperlayer()
}
}
let gradient = CAGradientLayer()
var rect = self.bounds
rect.size.width = ScreenWidth
gradient.frame = rect
gradient.colors = [firstColor.cgColor, secondColor.cgColor]
gradient.locations = locations as [NSNumber]
gradient.startPoint = CGPoint.init(x: 0, y: 0)
gradient.endPoint = CGPoint.init(x: 0, y: 1)
gradient.cornerRadius = radius
gradient.shadowRadius = 2
gradient.shadowColor = UIColor.lightGray.cgColor
gradient.shadowOffset = CGSize.init(width: 0.5, height: 0.5)
gradient.shadowOpacity = 0.5
self.layer.insertSublayer(gradient, at: 0)
}
}
try using this UIView's extension.Let me know if this helps.

I think your gradient layer add on your shadow view show your shadow view disappear..You should always add gradient layer at 0 index of layers.
bgView.layer.insertSublayer(CardCell.createGradientLayer(for: bgView), at: 0)
and Your layer creation method you need to use frame instead bounds.
private static func createGradientLayer(for view: UIView) -> CAGradientLayer {
let color = UIColor(red:0.95, green:0.42, blue:0.64, alpha:1.0)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = view.frame
gradientLayer.colors = [color.cgColor, color.withAlphaComponent(0.7).cgColor]
gradientLayer.locations = nil
return gradientLayer
}

The problem is When you add the gradient view the bgView is not layout completely. So the bound will be zero.
Solution:
private var gradient: CAGradientLayer?
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
shadowView.layer.shadowPath = UIBezierPath(rect: shadowView.bounds).cgPath
if let gradient = gradient {
gradient.frame = bgView.bounds
} else {
gradient = TestCell.createGradientLayer(for: bgView)
bgView.layer.addSublayer(gradient!)
}
}
OUTPUT:

Related

How to animate custom Progress bar properly (swift)?

I made a custom progressbar for my app (following an article on medium), it works as intended but i have one problem, when i change the progress value then it jumps to fast! (dont get confused by the percent values below the bar, they are off, i know that)
i use setNeedsDisplay() to redraw my view.
I want the bar to animate smoothly, so in my case a bit slower.
this is the draw function of the bar:
override func draw(_ rect: CGRect) {
backgroundMask.path = UIBezierPath(roundedRect: rect, cornerRadius: rect.height * 0.25).cgPath
layer.mask = backgroundMask
let progressRect = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height))
progressLayer.frame = progressRect
progressLayer.backgroundColor = UIColor.black.cgColor
gradientLayer.frame = rect
gradientLayer.colors = [color.cgColor, gradientColor.cgColor, color.cgColor]
gradientLayer.endPoint = CGPoint(x: progress, y: 0.5)
}
Here is the whole Class i used:
https://bitbucket.org/mariwi/custom-animated-progress-bars-with-uibezierpaths/src/master/ProgressBars/Bars/GradientHorizontalProgressBar.swift
Anyone with an idea?
EDIT 1:
Similar questions helped, but the result is not working properly.
I aded this function to set the progress of the bar:
func setProgress(to percent : CGFloat)
{
progress = percent
print(percent)
let rect = self.bounds
let oldBounds = progressLayer.bounds
let newBounds = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height))
let redrawAnimation = CABasicAnimation(keyPath: "bounds")
redrawAnimation.fromValue = oldBounds
redrawAnimation.toValue = newBounds
redrawAnimation.fillMode = .forwards
redrawAnimation.isRemovedOnCompletion = false
redrawAnimation.duration = 0.5
progressLayer.bounds = newBounds
gradientLayer.endPoint = CGPoint(x: progress, y: 0.5)
progressLayer.add(redrawAnimation, forKey: "redrawAnim")
}
And now the bar behaves like this:
After digging a while and a ton of testing, i came up with a solution, that suited my needs! Altough the above answer from DonMag was also working great (thanks for your effort), i wanted to fix what halfway worked. So the problem was, that the bar resized itself from the middle of the view. And on top, the position was also off for some reason.
First i set the position back to (0,0) so that the view started at the beginning (where it should).
The next thing was the resizing from the middle, because with the position set back, the bar only animated to the half when i set it to 100%. After some tinkering and reading i found out, that changing the anchorPoint of the view would solve my problem. The default value was (0.5,0.5), changing it into (0,0) meant that it would only expand the desired direction.
After that i only needed to re-set the end of the gradient, so that the animation stays consistent between the different values. After all of this my bar worked like I imagined. And here is the result:
Here is the final code, i used to accomplish this:
func setProgress(to percent : CGFloat)
{
progress = percent
print(percent)
let duration = 0.5
let rect = self.bounds
let oldBounds = progressLayer.bounds
let newBounds = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height))
let redrawAnimation = CABasicAnimation(keyPath: "bounds")
redrawAnimation.fromValue = oldBounds
redrawAnimation.toValue = newBounds
redrawAnimation.fillMode = .both
redrawAnimation.isRemovedOnCompletion = false
redrawAnimation.duration = duration
progressLayer.bounds = newBounds
progressLayer.position = CGPoint(x: 0, y: 0)
progressLayer.anchorPoint = CGPoint(x: 0, y: 0)
progressLayer.add(redrawAnimation, forKey: "redrawAnim")
let oldGradEnd = gradientLayer.endPoint
let newGradEnd = CGPoint(x: progress, y: 0.5)
let gradientEndAnimation = CABasicAnimation(keyPath: "endPoint")
gradientEndAnimation.fromValue = oldGradEnd
gradientEndAnimation.toValue = newGradEnd
gradientEndAnimation.fillMode = .both
gradientEndAnimation.isRemovedOnCompletion = false
gradientEndAnimation.duration = duration
gradientLayer.endPoint = newGradEnd
gradientLayer.add(gradientEndAnimation, forKey: "gradEndAnim")
}
I'm going to suggest a somewhat different approach.
First, instead of adding a sublayer as the gradient layer, we'll make the custom view's layer itself a gradient layer:
private var gradientLayer: CAGradientLayer!
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
// then, in init
// use self.layer as the gradient layer
gradientLayer = self.layer as? CAGradientLayer
We'll set the gradient animation to the full size of the view... that will give it a consistent width and speed.
Next, we'll add a subview as a mask, instead of a layer-mask. That will allow us to animate its width independently.
class GradProgressView: UIView {
#IBInspectable var color: UIColor = .gray {
didSet { setNeedsDisplay() }
}
#IBInspectable var gradientColor: UIColor = .white {
didSet { setNeedsDisplay() }
}
// this view will mask the percentage width
private let myMaskView = UIView()
// so we can calculate the new-progress-animation duration
private var curProgress: CGFloat = 0.0
public var progress: CGFloat = 0 {
didSet {
// calculate the change in progress
let changePercent = abs(curProgress - progress)
// if the change is 100% (i.e. from 0.0 to 1.0),
// we want the animation to take 1-second
// so, make the animation duration equal to
// 1-second * changePercent
let dur = changePercent * 1.0
// save the new progress
curProgress = progress
// calculate the new width of the mask view
var r = bounds
r.size.width *= progress
// animate the size of the mask-view
UIView.animate(withDuration: TimeInterval(dur), animations: {
self.myMaskView.frame = r
})
}
}
private var gradientLayer: CAGradientLayer!
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
// use self.layer as the gradient layer
gradientLayer = self.layer as? CAGradientLayer
gradientLayer.colors = [color.cgColor, gradientColor.cgColor, color.cgColor]
gradientLayer.locations = [0.25, 0.5, 0.75]
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
let animation = CABasicAnimation(keyPath: "locations")
animation.fromValue = [-0.3, -0.15, 0]
animation.toValue = [1, 1.15, 1.3]
animation.duration = 1.5
animation.isRemovedOnCompletion = false
animation.repeatCount = Float.infinity
gradientLayer.add(animation, forKey: nil)
myMaskView.backgroundColor = .white
mask = myMaskView
}
override func layoutSubviews() {
super.layoutSubviews()
// if the mask view frame has not been set at all yet
if myMaskView.frame.height == 0 {
var r = bounds
r.size.width = 0.0
myMaskView.frame = r
}
gradientLayer.colors = [color.cgColor, gradientColor.cgColor, color.cgColor]
layer.cornerRadius = bounds.height * 0.25
}
}
Here's a sample controller class - each tap will cycle through a list of sample progress percentages:
class ExampleViewController: UIViewController {
let progView = GradProgressView()
let infoLabel = UILabel()
var idx: Int = 0
let testVals: [CGFloat] = [
0.75, 0.3, 0.95, 0.25, 0.5, 1.0,
]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
[infoLabel, progView].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}
infoLabel.textColor = .white
infoLabel.textAlignment = .center
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
progView.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
progView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
progView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
progView.heightAnchor.constraint(equalToConstant: 40.0),
infoLabel.topAnchor.constraint(equalTo: progView.bottomAnchor, constant: 8.0),
infoLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
infoLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
])
progView.color = #colorLiteral(red: 0.9932278991, green: 0.5762576461, blue: 0.03188031539, alpha: 1)
progView.gradientColor = #colorLiteral(red: 1, green: 0.8578521609, blue: 0.3033572137, alpha: 1)
// add a tap gesture recognizer
let t = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
view.addGestureRecognizer(t)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
didTap(nil)
}
#objc func didTap(_ g: UITapGestureRecognizer?) -> Void {
let n = idx % testVals.count
progView.progress = testVals[n]
idx += 1
infoLabel.text = "Auslastung \(Int(testVals[n] * 100))%"
}
}

Adding Gradient View and UILabel Programmatically to a UIView Is Not Working

I have a Storyboard with three UIViews set up and connected to the storyboard's UIViewController.
#IBOutlet weak var availableView: UIView!
#IBOutlet weak var maybeAvailableView: UIView!
#IBOutlet weak var notAvailableView: UIView!
I have two functions to add a UILabel and CAGradientLayer to each of the UIViews. This one's for adding the UILabels.
func setUpLabels(view1: UIView, view2: UIView, view3: UIView) {
let availableLabel = UILabel()
let maybeAvailableLabel = UILabel()
let notAvailableLabel = UILabel()
availableLabel.text = "Available"
maybeAvailableLabel.text = "Maybe Available"
notAvailableLabel.text = "Not Available"
availableLabel.backgroundColor = .clear
maybeAvailableLabel.backgroundColor = .clear
notAvailableLabel.backgroundColor = .clear
availableLabel.font = UIFont.systemFont(ofSize: 17, weight: UIFont.Weight(rawValue: 10))
maybeAvailableLabel.font = UIFont.systemFont(ofSize: 17, weight: UIFont.Weight(rawValue: 10))
notAvailableLabel.font = UIFont.systemFont(ofSize: 17, weight: UIFont.Weight(rawValue: 10))
availableLabel.textColor = .black
maybeAvailableLabel.textColor = .black
notAvailableLabel.textColor = .black
availableLabel.frame = view1.bounds
maybeAvailableLabel.frame = view2.bounds
notAvailableLabel.frame = view3.bounds
view1.addSubview(availableLabel)
view2.addSubview(maybeAvailableLabel)
view3.addSubview(notAvailableLabel)
}
This one's for adding the gradients.
func setGradientBackground(colorTop: UIColor, colorBottom: UIColor, view: UIView) {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [colorBottom.cgColor, colorTop.cgColor]
gradientLayer.startPoint = CGPoint(x: 1, y: 1)
gradientLayer.endPoint = CGPoint(x: 0, y: 0)
gradientLayer.locations = [0, 1]
gradientLayer.frame = view.bounds
view.layer.insertSublayer(gradientLayer, at: 0)
}
This is what I call in viewDidLayoutSubviews
availableView.layer.masksToBounds = true
maybeAvailableView.layer.masksToBounds = true
notAvailableView.layer.masksToBounds = true
setGradientBackground(colorTop: darkBlue, colorBottom: .systemIndigo, view: notAvailableView)
setGradientBackground(colorTop: .systemRed, colorBottom: .systemOrange, view: maybeAvailableView)
setGradientBackground(colorTop: .systemBlue, colorBottom: .systemTeal, view: availableView)
setUpLabels(view1: availableView, view2: maybeAvailableView, view3: notAvailableView)
However, nothing appears in the viewController or in the debug hierarchy view. I've tried many things from other questions but nothing changes.
May be you have any issues with constraints. I've checked your code (I changed setGradientBackground(colorTop: .darkBlue, colorBottom: .systemIndigo, view: notAvailableView) to setGradientBackground(colorTop: .darkGray, colorBottom: .systemIndigo, view: notAvailableView) because I haven't this color and I see normal behavior:
Set gradient background to view
// - Parameters:
// - colors: gradient colors
// - opacity: opacity
// - direction: gradient direction
// - radius: radius
func setGradientBackground(_ colors: [UIColor], opacity: Float = 1, direction: GradientColorDirection = .vertical, radius: CGFloat = 25) {
if let sublayers = self.layer.sublayers {
for item in sublayers {
if item is CAGradientLayer {
item.removeFromSuperlayer()
}
}
}
let gradientLayer = CAGradientLayer()
gradientLayer.opacity = opacity
gradientLayer.colors = colors.map { $0.cgColor }
if case .horizontal = direction {
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
}
gradientLayer.bounds = self.bounds
gradientLayer.cornerRadius = radius
gradientLayer.anchorPoint = CGPoint.zero
self.layer.insertSublayer(gradientLayer, at: 0)
}
Gradient color direction
enum GradientColorDirection {
case vertical
case horizontal
}
Color for top to bottom masking
static let topToBottomMask: [UIColor] = {
return [UIColor.clear, UIColor.black.withAlphaComponent(0.40), UIColor.black.withAlphaComponent(0.43)]
}()
Set the gradient
self.view.setGradientBackground(topToBottomMask, radius: 0)
Hope it helps.

Gradient Color Swift

Here is what I am trying to do:
The screenshot is taken from Iphone:
This is my code:
#IBOutlet weak var viewBottomBorder: UIView!
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
let whiteColor = UIColor.black
gradient.colors = [whiteColor.withAlphaComponent(0.0).cgColor, whiteColor.withAlphaComponent(1.0), whiteColor.withAlphaComponent(1.0).cgColor]
gradient.locations = [NSNumber(value: 0.0),NSNumber(value: 0.2),NSNumber(value: 1.0)]
gradient.frame = viewBottomBorder.bounds
viewBottomBorder.layer.mask = gradient
Question: How to show same text in white color with gradient?
Can someone please explain to me how to solve this , i've tried to solve this issue but no results yet.
Any help would be greatly appreciated.
Thanks in advance.
You need to start your gradient at the top, because it's darker at the top. So x should be have max alpha. Then as y increases reduce the alpha.
Try this:
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 1.0, y: 0.0)
gradient.endPoint = CGPoint(x: 0.0, y: 1.0)
let whiteColor = UIColor.black
gradient.colors = [whiteColor.withAlphaComponent(1.0).cgColor, whiteColor.withAlphaComponent(1.0), whiteColor.withAlphaComponent(0.0).cgColor]
gradient.locations = [NSNumber(value: 1.0),NSNumber(value: 0.7),NSNumber(value: 0.0)]
gradient.frame = viewBottomBorder.bounds
viewBottomBorder.layer.mask = gradient
A little alternative:
func setupGradient(on view: UIView, withHeight height: CGFloat) {
// this is view that holds gradient
let gradientHolderView = UIView()
gradientHolderView.backgroundColor = .clear
gradientHolderView.translatesAutoresizingMaskIntoConstraints = false
// here you set layout programmatically (you can create this view in storyoard as well and attach gradient to it)
// make sure to position this view under your text
view.addSubview(gradientHolderView) // alternative: view.insertSubview(gradientHolderView, belowSubview: YourTextLaber)
gradientHolderView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
gradientHolderView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
gradientHolderView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
gradientHolderView.heightAnchor.constraint(equalToConstant: height).isActive = true
// this is needed to kinda refresh layout a little so later we can get bounds from view. I'm not sure exactly why but without this if you create view programmatically it is needed
gradientHolderView.setNeedsLayout()
gradientHolderView.layoutIfNeeded()
// here you create gradient as layer and add it as a sublayer on your view (modify colors as you like)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = gradientHolderView.bounds
gradientLayer.colors = [UIColor.clear.cgColor, UIColor(white: 0, alpha: 0.6).cgColor]
gradientHolderView.layer.addSublayer(gradientLayer)
}
Use above code to apply Gradient to your view
var gradientBackground : CAGradientLayer?
func applyGradientToBackground() {
if self.gradientBackground != nil {
self.gradientBackground?.removeFromSuperlayer()
}
self.gradientBackground = CAGradientLayer()
self.gradientBackground?.frame = self.your_view_name.bounds
let cor1 = UIColor.black.withAlphaComponent(1).cgColor
let cor2 = UIColor.white.cgColor
let arrayColors = [cor1, cor2]
self.gradientBackground?.colors = arrayColors
self.your_view_name.layer.insertSublayer(self.gradientBackground!, at: 0)
}

Gradient layer is not working in iOS

I have the code for making gradient but it's simply not showing. If I change the color of view that holds that gradient, I can see it. So the view is fine, just gradient has some issues. This is my code:
class KolodaCardView: UIView {
var helloWorld = "Hello World"
var userImage = UIImageView()
var userName = UILabel()
var parent = UIView()
var gradient = CAGradientLayer()
var gradientView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
parent = self
parent.backgroundColor = .clear
parent.layer.cornerRadius = 16
parent.clipsToBounds = true
setupUserImage()
setupUserName()
}
override func layoutSubviews() {
super.layoutSubviews()
gradient.frame = gradientView.frame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupUserImage() {
parent.addSubview(userImage)
userImage.snp.makeConstraints { make in
make.top.equalTo(parent)
make.bottom.equalTo(parent)
make.left.equalTo(parent)
make.right.equalTo(parent)
}
userImage.contentMode = .scaleAspectFill
userImage.clipsToBounds = true
userImage.layer.cornerRadius = 16
userImage.addSubview(gradientView)
gradientView.snp.makeConstraints { (make) in
make.bottom.equalToSuperview()
make.left.equalToSuperview()
make.right.equalToSuperview()
make.height.equalTo(60)
}
// gradientView.backgroundColor = .green
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 0, y: 1)
gradient.locations = [0.5,1.0]
gradient.frame = gradientView.bounds
gradient.colors = [UIColor.red.cgColor, UIColor.yellow.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradientView.layer.insertSublayer(gradient, at: 0)
}
func setupUserName() {
parent.addSubview(userName)
userName.snp.makeConstraints { (make) in
make.left.equalTo(parent).offset(16)
make.right.equalTo(parent)
make.height.equalTo(20)
make.bottom.equalTo(-20)
}
userName.textColor = .black
userName.textAlignment = .left
}
}
I checked several solutions here but nothing works! Can somebody check if maybe I am overlooking something?
In Gradient you have to give location of your gradient color that fill your layer with their start point to end point.
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0, y: 1)
gradientLayer.colors = [UIColor.red.cgColor ,UIColor.yellow.cgColor]
gradientLayer.locations = [0.5,1.0]
your_gradientView.layer.insertSublayer(gradientLayer, at: 0)

Improve Performance of Gradient Border using CAShapeLayer and CAGradientLayer

I am using this method to apply gradient border to views. But when the view is in a cell of a tableview, the scrolling frame rate of the table view drops significally. Is there a way to improve the performance ? I tried setting the opaque , drawsAsynchronously and shouldRasterize to true as Apple is suggesting but nothing changed.
func addBorder(colors:[UIColor]? = nil,size:CGSize? = nil) {
_ = self.sublayers?.filter({$0.name == "GradientBorder"}).map({$0.removeFromSuperlayer()})
let shapeFrame = CGRect(origin: CGPointZero, size: size ?? bounds.size)
let gradientLayer = CAGradientLayer()
gradientLayer.name = "GradientBorder"
gradientLayer.frame = shapeFrame
gradientLayer.startPoint = CGPointMake(0.0, 0.5)
gradientLayer.endPoint = CGPointMake(1.0, 0.5)
gradientLayer.colors = colors == nil ? [UIColor.blueColor().CGColor,UIColor.redColor().CGColor] : colors!.map({$0.CGColor})
gradientLayer.contentsScale = UIScreen.mainScreen().scale
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 2
shapeLayer.path = UIBezierPath(roundedRect: shapeFrame, cornerRadius: self.cornerRadius).CGPath
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.blackColor().CGColor
gradientLayer.shouldRasterize = true
gradientLayer.opaque = true
gradientLayer.drawsAsynchronously = true
shapeLayer.drawsAsynchronously = true
shapeLayer.opaque = true
gradientLayer.mask = shapeLayer
self.addSublayer(gradientLayer)
}
Ok i found the solution and it was very easy. I simply added these three lines.
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.layer.shouldRasterize = true
self.opaque = true
self.layer.rasterizationScale = UIScreen.mainScreen().scale
}

Resources