How to make a UIView have an effect of transparent gradient? - ios

I want to make a UIView have an effect of transparent gradient from the middle to the left and right. Like in this example:
The word 籍 has the desired effect. This view is achieved by the class MarqueeLabel. I examined the source code, it is likely implemented by class CALayer.

In Swift 4: for top to bottom transparent gradient.
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 0.6)
let whiteColor = UIColor.white
gradient.colors = [whiteColor.withAlphaComponent(0.0).cgColor, whiteColor.withAlphaComponent(1.0).cgColor, whiteColor.withAlphaComponent(1.0).cgColor]
gradient.locations = [NSNumber(value: 0.0),NSNumber(value: 0.2),NSNumber(value: 1.0)]
gradient.frame = gradientView.bounds
gradientView.layer.mask = gradient

Screenshot
Swift code
let mask = CAGradientLayer()
mask.startPoint = CGPointMake(0.0, 0.5)
mask.endPoint = CGPointMake(1.0, 0.5)
let whiteColor = UIColor.whiteColor()
mask.colors = [whiteColor.colorWithAlphaComponent(0.0).CGColor,whiteColor.colorWithAlphaComponent(1.0),whiteColor.colorWithAlphaComponent(1.0).CGColor]
mask.locations = [NSNumber(double: 0.0),NSNumber(double: 0.2),NSNumber(double: 1.0)]
mask.frame = label.bounds
label.layer.mask = mask

You can use CAGradientLayer as following.
gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = baseView.bounds;
gradientLayer.startPoint = CGPointMake(0.5,0.0);
gradientLayer.endPoint = CGPointMake(0.5,1.0);
gradientLayer.locations = #[#(0.0), #(0.2), #(1.0)];
gradientLayer.colors = #[(id)[UIColor colorWithWhite:1.0 alpha:0.9].CGColor,
(id)[UIColor colorWithWhite:1.0 alpha:0.3].CGColor,
(id)[UIColor colorWithWhite:1.0 alpha:0.0].CGColor];
[baseView.layer addSublayer:gradientLayer];
CAGradientLayer supports several properties to make natural gradient, such as setting gradient direction by startPoint and endPoint, changing color curve by locations and colors.
You also make a transparent effect by using alpha channel of color.

Swift 3:
let mask = CAGradientLayer()
mask.startPoint = CGPoint(x: 0, y: 0.5)
mask.endPoint = CGPoint(x:1.0, y:0.5)
let whiteColor = UIColor.white
mask.colors = [whiteColor.withAlphaComponent(0.0).cgColor,whiteColor.withAlphaComponent(1.0),whiteColor.withAlphaComponent(1.0).cgColor]
mask.locations = [NSNumber(value: 0.0),NSNumber(value: 0.2),NSNumber(value: 1.0)]
mask.frame = view.bounds
view.layer.mask = mask

Use clear color instead of set the alpha value.
let gradientLayer = CAGradientLayer()
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
gradientLayer.colors = [UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.white.cgColor]
gradientLayer.locations = [0, 0.2, 1]
gradientLayer.frame = gradientView.bounds
gradientView.layer.mask = gradientLayer

Related

How do you design a gradient for a layer in iOS?

I have to follow through my designer's gradient layer as shown below and I'm running into a wall trying to replicate her design (below).
I have the following code to try to replicate the same shadow but it is too solid compared to her gradient. How do I reduce my layer to have a gradient look and feel?
backgroundView.layer.shadowColor = UIColor.Custom.darkBlue.cgColor
backgroundView.layer.shadowOpacity = 1.0
backgroundView.layer.shadowRadius = 10
EDIT:
I implemented what I needed using #Frankenstein's solution below.
backgroundView.backgroundColor = UIColor.Custom.darkBlue
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [UIColor.black.cgColor, UIColor.Custom.darkBlue.cgColor]
gradient.frame = CGRect(x: backgroundView.frame.origin.x, y: backgroundView.frame.origin.y - 39, width: view.bounds.width, height: 40)
view.layer.addSublayer(gradient)
With the expected result below. Thank you!
You need to add a new CAGradientLayer and not set the shadow, here is an example:
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [UIColor.black.cgColor, UIColor.Custom.darkBlue.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradient.frame = view.bounds
view.layer.addSublayer(gradient)
Here is how you can achieve that
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [UIColor.black.cgColor, UIColor.blue.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x : 0.0, y : 0)
gradient.endPoint = CGPoint(x :0.0, y: 0.15) // you need to play with 0.15 to adjust gradient vertically
gradient.frame = view.bounds
view.layer.addSublayer(gradient)
With 0.15 to 0.5 you get

Create a UIView with leading / trailing faded edges

I have a UIView that I would like to apply a fade / gradient too. I'd like this to appear only on the edges, the effect I am trying to create is
The grey line at the top of the image. Grey in the middle and both edges are faded to white.
I have tried something like this
func render(content: FeedItem) {
print(content.item.externalId)
// rowSeperatorView.backgroundColor = UIColor.usingHex("f2f2f2")
iconContainerView.backgroundColor = UIColor.usingHex("3bac58")
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.frame = rowSeperatorView.bounds
gradientLayer.colors = [
UIColor.white.cgColor,
UIColor.usingHex("f2f2f2").cgColor,
UIColor.white.cgColor,
]
gradientLayer.locations = [0,0.5,1]
rowSeperatorView.layer.addSublayer(gradientLayer)
iconContainerView.layer.cornerRadius = 5
iconContainerView.clipsToBounds = true
iconContainerView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner]
}
But cannot seem to achieve this result.
You are almost there, try adding a startPoint and endPoint and then play with the locations property.
let gradient = CAGradientLayer()
gradient.frame = rowSeperatorView.bounds
gradient.colors = [UIColor.white.cgColor, UIColor.usingHex("f2f2f2").cgColor, UIColor.white.cgColor]
gradient.locations = [0, 0.4, 0.6]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 1.0, y: 0.0)
rowSeperatorView.layer.addSublayer(gradient)

How can I create a horizontal gradient background for my iOS nav bar?

I know how to set a navigation bar background color (with barTintColor), but now I am working on an iOS app that calls for a horizontal gradient (not the typical vertical gradient).
How can I create a navigation bar with a horizontal gradient background?
If you want to programmatically set the gradient of a given UINavigationBar I have a solution for you.
First setup a CAGradientLayer with your desired colors and locations.
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = navigationBar.bounds;
gradientLayer.colors = #[ (__bridge id)[UIColor greenColor].CGColor,
(__bridge id)[UIColor blueColor].CGColor ];
gradientLayer.startPoint = CGPointMake(0.0, 0.5);
gradientLayer.endPoint = CGPointMake(1.0, 0.5);
Then grab the UImage for that layer.
UIGraphicsBeginImageContext(gradientLayer.bounds.size);
[gradientLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Set the gradientImage as the backgroundImage for your UINavigationBar.
[navigationBar setBackgroundImage:gradientImage forBarMetrics:UIBarMetricsDefault];
Swift Solution:
[![// Setup the gradient
let gradientLayer = CAGradientLayer()
gradientLayer.frame = navigationBar.bounds
gradientLayer.colors = [UIColor.green.cgColor, UIColor.blue.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
// Render the gradient to UIImage
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Set the UIImage as background property
navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
Updated #JulianM answer for iOS 10 / swift 3.0:
let gradientLayer = CAGradientLayer()
var updatedFrame = self.navigationController!.navigationBar.bounds
updatedFrame.size.height += 20
gradientLayer.frame = updatedFrame
gradientLayer.colors = [UIColor.green.cgColor, UIColor.blue.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.navigationController!.navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
Swift
Add this function in global class
func setHorizontalGradientColor(view: UIView) {
let gradientLayer = CAGradientLayer()
var updatedFrame = view.bounds
updatedFrame.size.height += 20
gradientLayer.frame = updatedFrame
gradientLayer.colors = [UIColor.black.cgColor, UIColor.blue.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
view.layer.insertSublayer(gradientLayer, at: 0)
}
Use in anywhere:
setHorizontalGradientColor(view: self.bgView)
You can use that :
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"gardientImage"] forBarMetrics:UIBarMetricsDefault];
for ios 7 navigation bar height is 64px

Set a simple color gradient as the background of UIToolbar

I can easily change the UIToolbar background color thanks to the Bart Tint property in Interface Builder. However, I would like to use a simple, two-color vertical gradient as background.
The solution should work with any custom toolbar height, and my target is iOS 7+. If it must be done programmatically, both Objective-C and Swift are welcome.
Edit: based on the answers I'm doing this in viewDidLoad, but it makes no effect:
var gradient = CAGradientLayer()
gradient.frame = toolbar.bounds
gradient.colors = [UIColor.redColor(), UIColor.greenColor()]
toolbar.layer.insertSublayer(gradient, atIndex: 0)
Edit 2: based on the answers, I replaced the following line, but it still makes no effect:
gradient.colors = [UIColor.redColor().CGColor, UIColor.greenColor().CGColor]
Edit 3: I got it. I had to set "Bar Tint" to "Default" in Interface Builder first, so that the tint is transparent and doesn't hide the programmatically added gradient layer.
You can use CAGradientLayer for achieving this.
Objective C:
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = yourToolbar.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor redColor] CGColor], (id)[[UIColor greenColor] CGColor], nil];
[yourToolbar.layer insertSublayer:gradient atIndex:0];
Swift:
var gradient:CAGradientLayer = CAGradientLayer()
gradient.frame = yourToolbar.bounds
gradient.colors = [UIColor.redColor().CGColor, UIColor.greenColor().CGColor]
yourToolbar.layer.insertSublayer(gradient, atIndex: 0)
This works
var gradient:CAGradientLayer = CAGradientLayer()
gradient.frame = self.toolbar.bounds
gradient.colors = [UIColor.redColor().CGColor, UIColor.greenColor().CGColor]
self.toolbar.layer.insertSublayer(gradient, atIndex: 0)
It's the same way as setting a Gradient Background for UINavigationBar - you can use the setBackgroundImage method of UIToolbar.
Just add these two extensions:
extension UIImage {
static func imageFromLayer (layer: CALayer) -> UIImage? {
UIGraphicsBeginImageContext(layer.frame.size)
guard let currentContext = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in: currentContext)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage
}
}
extension UIToolbar {
func setGradientBackground(barFrame: CGRect, aColor: UIColor, bColor: UIColor, aX: CGFloat, bX: CGFloat, aY: CGFloat, bY: CGFloat) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = frame
gradientLayer.colors = [aColor.cgColor, bColor.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: aX, y: aY)
gradientLayer.endPoint = CGPoint(x: bX, y: bY)
if let image = UIImage.imageFromLayer(layer: gradientLayer) {
self.setBackgroundImage(image, forToolbarPosition: .bottom, barMetrics: .default)
}
}
}
This creates a UIImage from a CAGradientLayer, and subsequently sets it as a background image of your UIToolbar. Then just apply it to your UIToolbar. For instance, a horizontal gradient from blue to white:
myToolbar.setGradientBackground(
barFrame: navigationBar.frame,
aColor: UIColor.blue,
bColor: UIColor.white,
aX: 0.0,
bX: 1.0,
aY: 0.5,
bY: 0.5
)
Hope this helps!
// Use this Code:
i=2;
leftColor = [UIColor colorWithRed:0.03 green:0.20 blue:0.95 alpha:1.0];
rightColor = [UIColor colorWithRed:0.98 green:0.00 blue:0.89 alpha:1.0];
gradient.frame = self.font_imageview.bounds;
gradient.colors = [NSArray arrayWithObjects:
(id)[rightColor CGColor],
(id)[UIColor clearColor].CGColor,
(id)[leftColor CGColor],nil];
[font_imageview.layer insertSublayer:gradient atIndex:0];
gradient.startPoint = CGPointMake(0.0, 0.5);
gradient.endPoint = CGPointMake(1.0, 0.5);}
If you are using custom toolbar then maybe you face the size problem. view_toolbar can be any view, Here I found another perfect solution:
let gradientLayer = CAGradientLayer()
var bounds = self.view_toolbar.bounds
bounds.size.height += UIApplication.shared.statusBarFrame.size.height
gradientLayer.frame = bounds
gradientLayer.colors = [colorPrimary, colorPrimaryDark]
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
self.view_toolbar.layer.insertSublayer(gradientLayer, at: 0)

Fade the end of a label text

I have one UILabel, and i want to fade the end of the string, that is going to be out of bounds. What is the better solution for this?
Should i calculate the width of the label, compare it with the string width, and if string width is bigger than label's, i should fade last two letters? How exactly should i do that?
I hope it will be easy. Please write your solutions. Thanks!
I prefer to use this method for calculating the width:
CGRect labelRect = [text
boundingRectWithSize:labelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{
NSFontAttributeName : [UIFont systemFontOfSize:14]
}
context:nil];
Swift 4.0 example:
let gradient = CAGradientLayer()
gradient.frame = titleLabel.bounds
gradient.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
gradient.startPoint = CGPoint(x: 0.1, y: 0.0)
gradient.endPoint = CGPoint(x: 0.95, y: 0.0)
label.lineBreakMode = .byClipping
label.layer.mask = gradient
result:
You can fade one line label using CAGradientLayer
CAGradientLayer *l = [CAGradientLayer layer];
l.frame = self.textLabel.bounds;
l.colors = #[(id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor];
l.startPoint = CGPointMake(0.1f, 1.0f);
l.endPoint = CGPointMake(0.95f, 1.0f);
self.textLabel.layer.mask = l;
Works only from layoutSubviews() method
override func layoutSubviews() {
super.layoutSubviews()
let maskLayer = CALayer()
maskLayer.frame = label.bounds
let gradientLayer = CAGradientLayer()
gradientLayer.frame = label.bounds
gradientLayer.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.7, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.95, y: 0.0)
maskLayer.addSublayer(gradientLayer)
label.layer.mask = maskLayer
}
2023. Typical OUTLINE solution:
It does not take in to account language direction, it assumes background is white, etc etc.
Note that you have to explicitly decide on and set the length of the fade, which, of course, will be constant through out the app, you can't use ".1 of the width of the text". Here we use the height of the label which works well.
class FadeyLabel: UIILabel {
lazy var fade: CAGradientLayer = {
let g = CAGradientLayer()
g.colors = [UIColor.white.withAlphaComponent(0).cgColor,
UIColor.white.withAlphaComponent(1).cgColor]
g.startPoint = CGPoint(x: 0, y: 0)
g.endPoint = CGPoint(x: 1, y: 0)
layer.addSublayer(g)
return g
}()
override func layoutSubviews() {
super.layoutSubviews()
fade.frame = CGRect(
origin: CGPoint(x: bounds.width - bounds.height, y: 0),
size: CGSize(width: bounds.height, height: bounds.height))
}
}
I've found the answer - i should use GTMFadeTruncatingLabelTest class from google

Resources