For my application I\'m using a TableView and using customized UITableViewCells.
I customized my cells via interface builder, not programmatically. Is there a way to als
answer by etayluz works fine but I added a couple changes:
Remove Gradient layer on every draw, so that it does not keep drawing and adding a new layer when redraw is necessary (for instance by calling .setNeedsDisplay()
on rotation).
@IBDesignable final class MFGradientView: UIView {
@IBInspectable var startColor: UIColor = UIColor.clear
@IBInspectable var endColor: UIColor = UIColor.clear
override func draw(_ rect: CGRect) {
layer.sublayers?.first?.removeFromSuperlayer()
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = CGRect(origin: CGPoint.zero, size: self.bounds.size)
gradient.colors = [startColor.cgColor, endColor.cgColor]
layer.insertSublayer(gradient, at: 0)
}
}
To draw a gradient, you will have to subclass and override the drawRect programmatically:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents
(colorSpace,
(const CGFloat[8]){1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f},
(const CGFloat[2]){0.0f,1.0f},
2);
CGContextDrawLinearGradient(context,
gradient,
CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMinY(self.bounds)),
CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMaxY(self.bounds)),
0);
CGColorSpaceRelease(colorSpace);
CGContextRestoreGState(context);
}
The easiest way, which keeps your cells in the interface builder, is probably to subclass a UIView to have it draw a gradient in its drawRect and place it in your cell behind the other subviews:
GradientView *gradientView = [[GradientView alloc] init];
gradientView.frame = cell.bounds;
[cell addSubview:gradientView];
[cell sendSubviewToBack:gradientView];
However, the best way to do it is probably not to use the interface builder for this and make a subclass of UITableViewCell. For advanced customization, interface builders tend to only make things more complicated in my experience. That's up to personal preference though.
Based on etayluz answer I changed the code a little bit by taking the layerClass property of a UIView into account, so you do not need a separate layer as a sublayer.
I think it is much cleaner and it also works with live updates in the Interface Builder.
@IBDesignable final class GradientView: UIView {
@IBInspectable var startColor: UIColor = UIColor.red
@IBInspectable var endColor: UIColor = UIColor.blue
override class var layerClass: AnyClass {
get {
return CAGradientLayer.self
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupGradient()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupGradient()
}
private func setupGradient() {
let gradient = self.layer as! CAGradientLayer
gradient.colors = [startColor.cgColor, endColor.cgColor]
}
}