How can i achieve this type of gradient in each cell? - ios

How can i achieve the gradient below each cell ?

You can try with following code:
class func addGradientInView(_ view : UIImageView , Color1 : UIColor , color2 : UIColor , cornerRadius : CGFloat, width : CGFloat) -> CAGradientLayer
{
view.layer.cornerRadius = cornerRadius
view.layer.masksToBounds = true
view.layer.layoutSublayers()
let labelGradient: CAGradientLayer = CAGradientLayer()
labelGradient.masksToBounds = true
labelGradient.frame = view.bounds
labelGradient.frame.size.width = width
labelGradient.frame.size.height = width
labelGradient.colors = [(Color1.cgColor as AnyObject), (color2.cgColor as AnyObject)]
view.layer.insertSublayer(labelGradient, at: 0)
return labelGradient
}
To call the above method:
addGradientInView(icon_Veges, Color1: darkGray_MaxAlpha,
color2:darkGray_MinAlpha,
cornerRadius: 0.0,
width:width)
Suppose: let darkGray_MaxAlpha = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 0.1)
let darkGray_MinAlpha = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 0.6)
Note: Put view, color 1, color 2, width according to your need.

Create a UIView and subview the items you wanted like Name, Place etc.
Then initialise an object of CAGradientLayer and set colors, locations and frame. Then sublayer the object to UIView.
Following is the code snippet I suggest.
let gradient = CAGradientLayer()
gradient.colors = [UIColor.blackColor().colorWithAlphaComponent(0).CGColor,UIColor.blackColor().colorWithAlphaComponent(0.3).CGColor]
gradient.locations = [0.1,1.0]
gradient.frame = gradientView.bounds
gradientView.layer.addSublayer(gradient)

Related

Why gradient layer in UITableViewCell not cover entire frame?

I try to make a standard gradient top-bottom with long UIView. But it's not full. The nib is part of UITableViewCell, so I don't have access to viewDidLayoutSubviews() as in this thread.
I've tried to call contentView.layoutIfNeeded() from the code version of this view. I called it when UITableView cellForRowAtIndexPath gets called. But it's no effect.
I prepare the gradient in awakeFromNib().
let colors = [
UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0).cgColor,
UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0).cgColor]
let gradient = CAGradientLayer()
gradient.frame = gradientView.bounds
gradient.colors = colors
gradientView.layer.insertSublayer(gradient, at: 0)
Is there something wrong with my code?
You should use view's boundsinstead of frame, because your layer is inside of the view, and the frame may have an offset.
The layout of the view is changed after awakeFromNib. So you should resize the layer in layoutSubviews of the view. For this create a property gradient and:
let gradient: CAGradientLayer = CAGradientLayer()
override func awakeFromNib() {
...
let colors = [
UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0).cgColor,
UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0).cgColor]
gradient.frame = bounds
gradient.colors = colors
gradientView.layer.insertSublayer(gradient, at: 0)
...
}
override func layoutSubviews() {
super.layoutSubviews()
gradient.frame = bounds
}
EDIT: An alternative is a custom view with own layer class:
public class GradientLayer: UIView {
#IBInspectable var startColor: UIColor! = UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1.0)
#IBInspectable var endColor: UIColor! = UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0)
override class var layerClass : AnyClass {
return CAGradientLayer.self
}
override func awakeFromNib() {
super.awakeFromNib()
let colors = [ startColor.cgColor, endColor.cgColor ]
if let gradient = self.layer as? CAGradientLayer {
gradient.colors = colors
}
}
}
This is more elegant, because you can replace the static colors with IB inspectables, and you have a reusable component view.
override func layoutSubviews() {
super.layoutSubviews()
if let gradient = baseView.layer.sublayers?[0] as? CAGradientLayer {
gradient.frame = self.bounds
}
}

Why are these buttons not displaying correctly in larger screen devices? (Swift)

I have laid out my app in Xcode using iPhone SE view. The buttons etc all appear under testing how they should.
However when I test in a large screen, i.e iPhone 7 a couple of weird things happen.
1) Buttons hug the right hand side even though I have the constraints set to be 20px from margins
And secondly, a the gradient that I have applied to my buttons seems to stop 3/4 across the button in this instance:
It is the same code being called in each instance of the buttons:
let orangeGradient = CAGradientLayer().orangeButtonColor()
orangeGradient.frame = self.joinCommunityButton.bounds
self.joinCommunityButton.layer.insertSublayer(orangeGradient, at: 0)
extension CAGradientLayer {
func bespokeColor() -> CAGradientLayer {
let topColor = UIColor(red: (46/255.0), green: (63/255.0),blue: (81/255.0), alpha: 1)
let bottomColor = UIColor(red: (22/255.0), green: (31/255.0),blue: (41/255.0), alpha: 1)
let gradientColors: [CGColor] = [topColor.cgColor, bottomColor.cgColor]
let gradientLocations: [Float] = [0.0, 1.0]
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations as [NSNumber]?
return gradientLayer
}
func orangeButtonColor() -> CAGradientLayer {
let topColor = UIColor(red: (211/255.0), green: (115/255.0),blue: (28/255.0), alpha: 1)
let bottomColor = UIColor(red: (171/255.0), green: (80/255.0),blue: (14/255.0), alpha: 1)
let gradientColors: [CGColor] = [topColor.cgColor, bottomColor.cgColor]
let gradientLocations: [Float] = [0.0, 1.0]
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations as [NSNumber]?
return gradientLayer
}
func purpleButtonColor() -> CAGradientLayer {
let topColor = UIColor(red: (112/255.0), green: (41/255.0),blue: (183/255.0), alpha: 1)
let bottomColor = UIColor(red: (85/255.0), green: (19/255.0),blue: (159/255.0), alpha: 1)
let gradientColors: [CGColor] = [topColor.cgColor, bottomColor.cgColor]
let gradientLocations: [Float] = [0.0, 1.0]
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations as [NSNumber]?
return gradientLayer
}
func greenButtonColor() -> CAGradientLayer {
let topColor = UIColor(red: (35/255.0), green: (193/255.0),blue: (67/255.0), alpha: 1)
let bottomColor = UIColor(red: (31/255.0), green: (148/255.0),blue: (53/255.0), alpha: 1)
let gradientColors: [CGColor] = [topColor.cgColor, bottomColor.cgColor]
let gradientLocations: [Float] = [0.0, 1.0]
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations as [NSNumber]?
return gradientLayer
}
}
Here is an screenshot of what I believe are the auto layout settings:
In viewDidLoad, autoLayout hasn't taken effect yet so your button bounds are not device specific.
Put
orangeGradient.frame = self.joinCommunityButton.bounds in viewDidLayoutSubviews or viewDidAppear
Make sure to add gradients or perform tasks related to UIView frame or bounds after viewDidLayoutSubviews has been called if you are using autoLayout.
Also,
Don't put the initialization of the CAGradientLayer() inside the viewDidAppear or viewDidLayoutSubviews functions as they are called multiple times and will keep adding layers to your UIView, you should just change the bounds inside the two methods.
Please make sure you are using AutoLayout in interface builder.If you are using then make sure they have left margin too.

Changing gradient background like in Instagram Log In

How to make changing gradient background like in Instagram Log In?
In Android you do it like this:
Is there a similar way to do it in Swift?
If you want to change continuously change view's background color with animation you can set it something like this.
var colors: [UIColor] = [.red, .blue, .green]
func startAnimation(index: Int) {
UIView.animate(withDuration: 2.5, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
self.view.backgroundColor = self.colors[index]
}) { (finished) in
var currentIndex = index + 1
if currentIndex == self.colors.count { currentIndex = 0 }
self.startAnimation(index: currentIndex)
}
}
And call this function with index 0.
self.startAnimation(index: 0)
In Swift3
Use CAGradientLayer with Using CABasicAnimation
I create PastelView Library to make alike instgram background animation effect
repo https://github.com/cruisediary/Pastel
Colors
var colors: [UIColor] = [UIColor(red: 156/255, green: 39/255, blue: 176/255, alpha: 1.0),
UIColor(red: 255/255, green: 64/255, blue: 129/255, alpha: 1.0),
UIColor(red: 123/255, green: 31/255, blue: 162/255, alpha: 1.0),
UIColor(red: 32/255, green: 76/255, blue: 255/255, alpha: 1.0),
UIColor(red: 32/255, green: 158/255, blue: 255/255, alpha: 1.0),
UIColor(red: 90/255, green: 120/255, blue: 127/255, alpha: 1.0),
UIColor(red: 58/255, green: 255/255, blue: 217/255, alpha: 1.0)]
Set Gradient
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = currentGradientSet()
gradient.startPoint = CGPoint(x:0, y:1)
gradient.endPoint = CGPoint(x:1, y:0)
gradient.drawsAsynchronously = true
layer.insertSublayer(gradient, at: 0)
Add Animation to gradient
let animation = CABasicAnimation(keyPath: Animation.keyPath)
animation.duration = animationDuration
animation.toValue = currentGradientSet()
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
animation.delegate = self //this is important
gradient.add(animation, forKey: Animation.key)
After end animation loop another color set looping
extension PastelView: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if flag {
gradient.colors = currentGradientSet()
animateGradient()
}
}
}
Pastel should help you :)
You can do it pretty easily using CAGradientLayer:
let grad = CAGradientLayer()
grad.colors = [
UIColor.red.cgColor, // top color
UIColor.blue.cgColor // bottom color
]
grad.locations = [
0.0, // start gradating at top of view
1.0 // end gradating at bottom of view
]
grad.frame = view.bounds
view.layer.addSublayer(grad)
You could increase the first item in locations (0.0) to start the gradating further down, or you could decrease 1.0 to complete gradation higher up. It's a bit tough to explain, drop this into a playground and mess around a bit until you get your desired effect.
Example gradient and playground from the code above:
You can do like this in SWIFT 3. You can give more colors in it.
let gradient1 = CAGradientLayer()
gradient1.frame = CGRect(origin: CGPoint.zero , size: CGSize (width: self.view.frame.size.width,height: self.view.frame.size.height))
gradient1.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
print(gradient1.frame)
view_gradient.layer.masksToBounds = true
view_gradient.layer.addSublayer(gradient1)
Hope this works for you.

Background gradient not see correctly in mode landscape

When I put the device in mode landscape, the background is set wrong. How do I fix it? I also could use to know how to put the entire application in landscape mode.
override func viewDidLoad() {
super.viewDidLoad()
//BACKGROUND FONDO
//A linear Gradient Consists of two colours: top colour and bottom colour
let topColor = UIColor(red: 15.0/255.0, green: 118.0/255.0, blue: 128.0/255.0, alpha: 1.0)
let bottomColor = UIColor(red: 84.0/255.0, green: 187.0/255.0, blue: 187.0/255.0, alpha: 1.0) 
//Add the top and bottom colours to an array and setup the location of those two.
let gradientColors: [CGColor] = [topColor.CGColor, bottomColor.CGColor]
let gradientLocations: [CGFloat] = [0.0, 1.0]
//Create a Gradient CA layer
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
gradientLayer.frame = self.view.bounds
self.view.layer.insertSublayer(gradientLayer, atIndex: 0)
} //FIN BACKGROUND GRADIENT
In your case gradient is a Layer, not View. It means that it will not resize or change position while the containing layer changes (e.g. during rotation). You have to change the frame of the sublayer manually during rotation.
var gradientLayer = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
createGredientBackground()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
gradientLayer.frame = view.layer.bounds
}
func createGredientBackground() {
let colorTop = UIColor(red: 255.0/255.0, green: 149.0/255.0, blue: 0.0/255.0, alpha: 1.0).cgColor
let colorBottom = UIColor(red: 255.0/255.0, green: 94.0/255.0, blue: 58.0/255.0, alpha: 1.0).cgColor
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.frame = self.view.bounds
self.view.layer.insertSublayer(gradientLayer, at:0)
}

CALayer not resizing with Autolayout

I have created a progress bar to be used in a tableView by creating a gradient layer. It works perfectly.
iPhone5:
In order to use the app on multiple devices, I have created the UIView in Storyboard, tagged it and added constraints.
However, when I use the app on an iPhone 6 the CALayer don't resize.
iPhone6:
I find this extremely stupid, but never mind. I have looked around and tried to understand how to solve this for months, but I have come up short. Does ANYONE know how to make CALayers resize with the UIView? Any help would be very much appreciated ! Thank you.
progressBar = cell.contentView.viewWithTag(3) as UIView!
progressBar.layer.cornerRadius = 4
progressBar.layer.masksToBounds = true
// create gradient layer
let gradient : CAGradientLayer = CAGradientLayer()
// create color array
let arrayColors: [AnyObject] = [
UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor,
UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor]
// set gradient frame bounds to match progressBar bounds
gradient.frame = progressBar.bounds
// set gradient's color array
gradient.colors = arrayColors
//Set progress(progressBar)
var percentageCompleted = 0.6
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.locations = [percentageCompleted, percentageCompleted]
gradient.endPoint = CGPoint(x: 1, y: 0.5)
// replace base layer with gradient layer
progressBar.layer.insertSublayer(gradient, atIndex: 0)
The default layer of a UIView does resize with its view, but sublayers don't (as you found out). One way to make this work is to create a custom view class, move the code you have in your question to it, and override layoutSublayersOfLayer where you can set the gradient layer to be the same size as the view. Because this code is now in a custom class, I also created a property percentageCompleted (instead of a local variable), and added a willSet clause so the bar's appearance is updated any time you change the percentageCompleted property.
class RDProgressView: UIView {
private let gradient : CAGradientLayer = CAGradientLayer()
var percentageCompleted: Double = 0.0 {
willSet{
gradient.locations = [newValue, newValue]
}
}
override func awakeFromNib() {
self.layer.cornerRadius = 4
self.layer.masksToBounds = true
// create color array
let arrayColors: [AnyObject] = [
UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor,
UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor]
// set gradient's color array
gradient.colors = arrayColors
//Set progress(progressBar)
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.locations = [percentageCompleted, percentageCompleted]
gradient.endPoint = CGPoint(x: 1, y: 0.5)
self.layer.insertSublayer(gradient, atIndex: 0)
}
override func layoutSublayersOfLayer(layer: CALayer!) {
super.layoutSublayersOfLayer(layer)
gradient.frame = self.bounds
}
}
In IB, you would change the class of your view to RDProgressView (in my example), and in cellForRowAtIndexPath, you would only need to get a reference to the view, and set its percentageCompleted property.
progressBar = cell.contentView.viewWithTag(3) as RDProgressView!
progressBar.percentageCompleted = 0.2
As an alternative to the accepted answer, you could also change the views layer class to be CAGradientLayer. The views layer will always be resized according to layout changes. You can achieve that by subclassing UIView
class GradientView: UIView {
override class func layerClass() -> AnyClass {
return CAGradientLayer.self
}
}
then set the colors
if let gradientLayer = gradientView.layer as? CAGradientLayer {
gradientLayer.colors = arrayColors
}
It's less code than adding and maintaining a sublayer, but might not suit all use cases.

Resources