I want to achieve this effect on UIViews and UIImageViews:


On UIView I know I can put 2 inside of it with different colors, but I pretty much think there must be a better way and I don't know how to do it in the UIImageVIew. Some sort of pod would be really useful because I couldn't find one.
You could add a gradient layer where instead of making a transition from one color to another you would go from a color to the same color until the middle point, and the same with the second half. Check the example:
let twoColorView = UIView(frame: CGRect(x: 40, y: 100, width: 200, height: 100))
let gradientLayer = CAGradientLayer()
gradientLayer.frame = twoColorView.bounds
gradientLayer.colors = [UIColor.red.cgColor, UIColor.red.cgColor, UIColor.blue.cgColor, UIColor.blue.cgColor]
gradientLayer.locations = [NSNumber(value: 0.0), NSNumber(value: 0.5), NSNumber(value: 0.5), NSNumber(value: 1.0)]
twoColorView.layer.addSublayer(gradientLayer)
and of course you can style that view further, such as:
twoColorView.layer.cornerRadius = twoColorView.bounds.height / 2
twoColorView.layer.masksToBounds = true
It results in this:

EDIT:
It can be generalized to accept any number of colors. Create a UIView extension and add your logic there. In this way the colors can be applied to any UIView and its subclasses, such as UILabel, UIButton, UIImageView, etc.
extension UIView {
func addColors(colors: [UIColor]) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds
var colorsArray: [CGColor] = []
var locationsArray: [NSNumber] = []
for (index, color) in colors.enumerated() {
// append same color twice
colorsArray.append(color.cgColor)
colorsArray.append(color.cgColor)
locationsArray.append(NSNumber(value: (1.0 / Double(colors.count)) * Double(index)))
locationsArray.append(NSNumber(value: (1.0 / Double(colors.count)) * Double(index + 1)))
}
gradientLayer.colors = colorsArray
gradientLayer.locations = locationsArray
self.backgroundColor = .clear
self.layer.addSublayer(gradientLayer)
// This can be done outside of this funciton
self.layer.cornerRadius = self.bounds.height / 2
self.layer.masksToBounds = true
}
}
And adding colors:
let colorView = UIImageView(frame: CGRect(x: 40, y: 100, width: 200, height: 100))
colorView.addColors(colors: [.red, .green, .blue])
view.addSubview(colorView)
This is the result:

Be careful not to call this function multiple times in the lifecycle of the view, because it will add sublayers on top of each other. So either call it once or remove the sublayers before you call addColors again. So of course there is room for improvement.
a more static and objective way in Swift 4,
class ColouredView: UIView {
override class var layerClass : AnyClass {
return ColouredLayer.self
}
}
class ColouredLayer: CAGradientLayer{
override init() {
super.init()
let colors = [UIColor.red, UIColor.blue]
addColors(colors)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension CAGradientLayer{
func addColors(_ colors: [UIColor]){
var colorsArray: [CGColor] = []
var locationsArray: [NSNumber] = []
for (index, color) in colors.enumerated() {
// append same color twice
colorsArray.append(color.cgColor)
colorsArray.append(color.cgColor)
locationsArray.append(NSNumber(value: (1.0 / Double(colors.count)) * Double(index)))
locationsArray.append(NSNumber(value: (1.0 / Double(colors.count)) * Double(index + 1)))
}
self.colors = colorsArray
locations = locationsArray
}
}
just set and assign the ColouredView
Thanks to @Au Ris's answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With