UIButton gradient not working - iphone

I found this code from tutorial and tried to use it:
CAGradientLayer *btnGradient = [CAGradientLayer layer];
btnGradient.frame = button.bounds;
btnGradient.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:102.0f / 255.0f green:102.0f / 255.0f blue:102.0f / 255.0f alpha:1.0f] CGColor],
(id)[[UIColor colorWithRed:51.0f / 255.0f green:51.0f / 255.0f blue:51.0f / 255.0f alpha:1.0f] CGColor],
nil];
[button.layer insertSublayer:btnGradient atIndex:0];
The code is in viewDidLoad method.
button is defined like this in .h file: #property (nonatomic, strong) IBOutlet UIButton *button;
and it's #synthesized in .m file and it's connected in interface builder
I am able to do other customization to the button like changing its background color (solid color) and changing the color of text. But when I try to use gradient color the background is just transparent.
I appreciate your help!

You need to set the gradient layer's frame to cover the entire button. Chance is that at viewDidLoad the button's size is zero, which makes the gradient layer's frame zero... And later when the button's size changes, the gradient layer's frame doesn't changed accordingly.
Subclassing UIButton and overriding layoutSubviews is a good idea
#interface MyButton : UIButton {
}
#implementation MyButton {
CAGradientLayer* _gradient;
}
-(id)init {
self = [super init];
_gradient = [CAGradientLayer layer];
_gradient.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:102.0f / 255.0f green:102.0f / 255.0f blue:102.0f / 255.0f alpha:1.0f] CGColor],
(id)[[UIColor colorWithRed:51.0f / 255.0f green:51.0f / 255.0f blue:51.0f / 255.0f alpha:1.0f] CGColor],
nil];
[self.layer insertSublayer:_gradient atIndex:0];
}
-(void)layoutSubviews {
[super layoutSubviews];
_gradient.frame = self.bounds;
}
#end
Another option is to use observeValueForKeyPath... to detect changes in the button's frame, and resize the layer accordingly. Not a very reusable solution thought.

I had this problem where the gradient wasn't appearing. Like #khanhnguyen said the problem was I setting it in viewDidLoad and because of that the button's bounds was unknown so nothing was appearing.
When I moved the code to viewDidLayoutSubviews it appeared. Here is the answer in Swift:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let purpleColor = UIColor(red: 129/255, green: 52/255, blue: 175/255, alpha: 1)
let pinkColor = UIColor(red: 221/255, green: 42/255, blue: 123/255, alpha: 1)
let yellowColor = UIColor(red: 254/255, green: 218/255, blue: 119/255, alpha: 1)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = yourButton.bounds
gradientLayer.colors = [purpleColor.cgColor, pinkColor.cgColor, yellowColor.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
yourButton.layer.insertSublayer(gradientLayer, at: 0)
}
If using a collection view cell add it to:
override func layoutSubviews() {
super.layoutSubviews()
}

Probably first you need to set the frame button. Try this.
+ (UIButton*) buttonWithGradient:(CGSize)size beginColor:(UIColor*)beginColor endColor:(UIColor*)endColor
{
CGRect frame = { CGPointZero, size };
UIButton* button = [[UIButton alloc] initWithFrame:frame];
CAGradientLayer* gradient = [CAGradientLayer layer];
gradient.frame = frame;
gradient.colors = #[(id)beginColor.CGColor, (id)endColor.CGColor];
[button.layer insertSublayer:gradient atIndex:0];
return [button autorelease];
}

Related

How to create a top fade effect using UIScrollView?

I've got a UIScrollView in my app and I have seen in some other apps that when the user scrolls, the top section fades out on scroll rather than just dissapearing out.
I really love this effect and want to achieve it. Any ideas how it can be done?
Simple 2020 solution:
import UIKit
class FadeTail: UIIView {
private lazy var gradientLayer: CAGradientLayer = {
let l = CAGradientLayer()
l.startPoint = CGPoint(x: 0.5, y: 0)
l.endPoint = CGPoint(x: 0.5, y: 1)
let baseColor = UIColor.white // for example
l.colors = [
baseColor.withAlphaComponent(0),
baseColor.withAlphaComponent(1),
].map{$0.cgColor}
layer.addSublayer(l)
return l
}()
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
}
Simply
autolayout that view in storyboard,
any shape or size you wish
on top of the view (text, image, webview, anything) you wish to be faded.
Easy.
Tip - gradients, circles, etc
If you need crazy circular/banded/etc fades, use the techniques here: https://stackoverflow.com/a/61174086/294884
EDIT: I've put this code up on github, see here.
See my answer to a similar question.
My solution is to subclass UIScrollView, and create a mask layer in the layoutSubviews method.
#import "FadingScrollView.h"
#import <QuartzCore/QuartzCore.h>
static float const fadePercentage = 0.2;
#implementation FadingScrollView
// ...
- (void)layoutSubviews
{
[super layoutSubviews];
NSObject * transparent = (NSObject *) [[UIColor colorWithWhite:0 alpha:0] CGColor];
NSObject * opaque = (NSObject *) [[UIColor colorWithWhite:0 alpha:1] CGColor];
CALayer * maskLayer = [CALayer layer];
maskLayer.frame = self.bounds;
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(self.bounds.origin.x, 0,
self.bounds.size.width, self.bounds.size.height);
gradientLayer.colors = [NSArray arrayWithObjects: transparent, opaque,
opaque, transparent, nil];
// Set percentage of scrollview that fades at top & bottom
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:fadePercentage],
[NSNumber numberWithFloat:1.0 - fadePercentage],
[NSNumber numberWithFloat:1], nil];
[maskLayer addSublayer:gradientLayer];
self.layer.mask = maskLayer;
}
#end
The code above fades the top and bottom of the UIScrollView from the background colour to transparent, but this can be easily changed to fade the top only (or fade to any colour you want).
Change this line to fade the top only:
// Fade top of scrollview only
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:fadePercentage],
[NSNumber numberWithFloat:1],
[NSNumber numberWithFloat:1], nil];
EDIT 2:
Or fade the top only by changing these two lines:
// Fade top of scrollview only
gradientLayer.colors = [NSArray arrayWithObjects: transparent, opaque, nil];
gradientLayer.locations = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:fadePercentage], nil];
Or, fade the bottom only:
// Fade bottom of scrollview only
gradientLayer.colors = [NSArray arrayWithObjects: opaque, transparent, nil];
gradientLayer.locations = [NSArray arrayWithObjects: [NSNumber numberWithFloat:1.0 - fadePercentage],
[NSNumber numberWithFloat:1], nil];
You can use a CAGradientLayer by
Adding the QuartzCore.framework to your project (see Linking to Library or Framework).
Add #import of the QuartzCore headers:
#import <QuartzCore/QuartzCore.h>
And then use CAGradientLayer:
- (void)addGradientMaskToView:(UIView *)view
{
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = #[(id)[[UIColor clearColor] CGColor], (id)[[UIColor whiteColor] CGColor]];
gradient.startPoint = CGPointMake(0.5, 0.0); // this is the default value, so this line is not needed
gradient.endPoint = CGPointMake(0.5, 0.20);
[view.layer setMask:gradient];
}
Note, this CAGradientLayer is a gradient from a color with alpha of 0.0 (e.g. clearColor) to a color to a color with alpha of 1.0 (e.g. whiteColor), not just from black to white. You can adjust the startPoint (the default value is probably fine) and the endPoint to adjust where you want the gradient to be applied.
And generally, when doing this with a UIScrollView, unless you want the gradient to scroll with you, you make the UIScrollView a subview of some other UIView and apply this gradient to that container view, not the scroll view itself.
Thanks to Fattie's answer I created the following UIView extension, in Swift, that takes care of the gradient fading and provides more styles (bottom, top, left right, vertical and horizontal) as well as fade percentage.
For any comments/recommendations, please let me know at the gist I've created, I try to keep both that and this answer up to date with any changes I add.
The Extension:
extension UIView {
enum UIViewFadeStyle {
case bottom
case top
case left
case right
case vertical
case horizontal
}
func fadeView(style: UIViewFadeStyle = .bottom, percentage: Double = 0.07) {
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
let startLocation = percentage
let endLocation = 1 - percentage
switch style {
case .bottom:
gradient.startPoint = CGPoint(x: 0.5, y: endLocation)
gradient.endPoint = CGPoint(x: 0.5, y: 1)
case .top:
gradient.startPoint = CGPoint(x: 0.5, y: startLocation)
gradient.endPoint = CGPoint(x: 0.5, y: 0.0)
case .vertical:
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
gradient.colors = [UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.white.cgColor, UIColor.clear.cgColor]
gradient.locations = [0.0, startLocation, endLocation, 1.0] as [NSNumber]
case .left:
gradient.startPoint = CGPoint(x: startLocation, y: 0.5)
gradient.endPoint = CGPoint(x: 0.0, y: 0.5)
case .right:
gradient.startPoint = CGPoint(x: endLocation, y: 0.5)
gradient.endPoint = CGPoint(x: 1, y: 0.5)
case .horizontal:
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
gradient.colors = [UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.white.cgColor, UIColor.clear.cgColor]
gradient.locations = [0.0, startLocation, endLocation, 1.0] as [NSNumber]
}
layer.mask = gradient
}
}
You add an alpha mask layer to a view containing your scroll view like this:
CALayer *mask = [CALayer layer];
CGImageRef maskRef = [UIImage imageNamed:#"scrollMask"].CGImage;
CGImageRef maskImage = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
mask.contents = (__bridge id)maskImage;
mask.frame = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height);
view.layer.mask = mask;
view.layer.masksToBounds = YES;
CGImageRelease(maskImage);
where "scrollMask" is a grayscale image defining mask region: white == fully masked, black == not masked at all and gray == partially masked.
To create the effect you're looking for, the mask image would be black with a white gradient at the top like this:
For more details, take a look at the documentation for CGImageMaskCreate.
We built onto Steph Sharp's code to only fade when necessary. Our code is setup as a static utility method instead of a subclass so that we could reuse the method in our subclasses of UIScrollView and UITableView. Here is our static utility method:
#define kScrollViewFadeColorLight [UIColor colorWithRed:0.56 green:0.56 blue:0.56 alpha:0.0]
#define kScrollViewFadeColorDark [UIColor colorWithRed:0.56 green:0.56 blue:0.56 alpha:1.0]
#define kScrollViewScrollBarWidth 7.0
#define kScrollViewFadingEdgeLength 40.0
+ (void) applyFadeToScrollView:(UIScrollView*) scrollView {
CGFloat topOffset = -scrollView.contentInset.top;
CGFloat bottomOffset = scrollView.contentSize.height + scrollView.contentInset.bottom - scrollView.bounds.size.height;
CGFloat distanceFromTop = scrollView.contentOffset.y - topOffset;
CGFloat distanceFromBottom = bottomOffset - scrollView.contentOffset.y;
BOOL isAtTop = distanceFromTop < 1.0;
BOOL isAtBottom = distanceFromBottom < 1.0;
if (isAtTop && isAtBottom) {
// There is no scrolling to be done here, so don't fade anything!
scrollView.layer.mask = nil;
return;
}
NSObject* transparent = (NSObject*)[kScrollViewFadeColorLight CGColor];
NSObject* opaque = (NSObject*)[kScrollViewFadeColorDark CGColor];
CALayer* maskLayer = [CALayer layer];
maskLayer.frame = scrollView.bounds;
CALayer* scrollGutterLayer = [CALayer layer];
scrollGutterLayer.frame = CGRectMake(scrollView.bounds.size.width - kScrollViewScrollBarWidth, 0.0,
kScrollViewScrollBarWidth, scrollView.bounds.size.height);
scrollGutterLayer.backgroundColor = (__bridge CGColorRef)(opaque);
[maskLayer addSublayer:scrollGutterLayer];
CAGradientLayer* gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0.0, 0.0, scrollView.bounds.size.width, scrollView.bounds.size.height);
CGFloat fadePercentage = kScrollViewFadingEdgeLength / scrollView.bounds.size.height;
NSMutableArray* colors = [[NSMutableArray alloc] init];
NSMutableArray* locations = [[NSMutableArray alloc] init];
if (!isAtTop) {
[colors addObjectsFromArray:#[transparent, opaque]];
[locations addObjectsFromArray:#[#0.0, [NSNumber numberWithFloat:fadePercentage]]];
}
if (!isAtBottom) {
[colors addObjectsFromArray:#[opaque, transparent]];
[locations addObjectsFromArray:#[[NSNumber numberWithFloat:1.0 - fadePercentage], #1.0]];
}
gradientLayer.colors = colors;
gradientLayer.locations = locations;
[maskLayer addSublayer:gradientLayer];
scrollView.layer.mask = maskLayer;
}
Here is our usage of that method.
FadingScrollView.h
#interface FadingScrollView : UIScrollView
#end
FadingScrollView.m
#implementation FadingScrollView
- (void) layoutSubviews {
[super layoutSubviews];
[Utils applyFadeToScrollView:self];
}
#end
FadingTableView.h
#interface FadingTableView : UITableView
#end
FadingTableView.m
#implementation FadingTableView
- (void) layoutSubviews {
[super layoutSubviews];
[Utils applyFadeToScrollView:self];
}
#end

adding fading color & transparency to UIView

I know how to create and animate a view like the one in the Share sub view of the new app store app that comes with iOS 6+ (see attached screenshot), but I don't know how to add that nice coloring effect with transparency on this view.
anyone can provide a code sample to make a UIView looks exactly the one in the screenshot?
P.S. the alpha property alone of UIView does not do such thing.
You can add this method to a UIView category and reuse as needed.
It applies a linear black gradient from "theColor" to transparent to the given view.
You should have QuartzCore.framework in your project in order to use the CAGradientLayer object.
+ (void)addLinearGradientToView:(UIView *)theView withColor:(UIColor *)theColor transparentToOpaque:(BOOL)transparentToOpaque
{
CAGradientLayer *gradient = [CAGradientLayer layer];
//the gradient layer must be positioned at the origin of the view
CGRect gradientFrame = theView.frame;
gradientFrame.origin.x = 0;
gradientFrame.origin.y = 0;
gradient.frame = gradientFrame;
//build the colors array for the gradient
NSArray *colors = [NSArray arrayWithObjects:
(id)[theColor CGColor],
(id)[[theColor colorWithAlphaComponent:0.9f] CGColor],
(id)[[theColor colorWithAlphaComponent:0.6f] CGColor],
(id)[[theColor colorWithAlphaComponent:0.4f] CGColor],
(id)[[theColor colorWithAlphaComponent:0.3f] CGColor],
(id)[[theColor colorWithAlphaComponent:0.1f] CGColor],
(id)[[UIColor clearColor] CGColor],
nil];
//reverse the color array if needed
if(transparentToOpaque)
{
colors = [[colors reverseObjectEnumerator] allObjects];
}
//apply the colors and the gradient to the view
gradient.colors = colors;
[theView.layer insertSublayer:gradient atIndex:0];
}
Please note that you should have the backgroundColor of theView set to clearColor so that it doesn't interfere with the gradient.
Also, for the results shown in the screenshot, the transparentToOpaque flag should be YES.
Here is PedroSilva's solution translated to Swift if anyone needs it (added vertical option as well)
class func addLinearGradientToView(view: UIView, colour: UIColor, transparntToOpaque: Bool, vertical: Bool)
{
let gradient = CAGradientLayer()
let gradientFrame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)
gradient.frame = gradientFrame
var colours = [
colour.CGColor,
colour.colorWithAlphaComponent(0.9).CGColor,
colour.colorWithAlphaComponent(0.8).CGColor,
colour.colorWithAlphaComponent(0.7).CGColor,
colour.colorWithAlphaComponent(0.6).CGColor,
colour.colorWithAlphaComponent(0.5).CGColor,
colour.colorWithAlphaComponent(0.4).CGColor,
colour.colorWithAlphaComponent(0.3).CGColor,
colour.colorWithAlphaComponent(0.2).CGColor,
colour.colorWithAlphaComponent(0.1).CGColor,
UIColor.clearColor().CGColor
]
if transparntToOpaque == true
{
colours = colours.reverse()
}
if vertical == true
{
gradient.startPoint = CGPointMake(0, 0.5)
gradient.endPoint = CGPointMake(1, 0.5)
}
gradient.colors = colours
view.layer.insertSublayer(gradient, atIndex: 0)
}
CAGradientLayer *layer = [CAGradientLayer layer];
layer.frame = yourView.bounds;
UIColor *blackColor = [UIColor colorWithWhite:0.42f alpha:1.0f];
UIColor *clearColor = [UIColor colorWithWhite:0.42f alpha:0.0f];
layer.colors = [NSArray arrayWithObjects:(id)clearColor.CGColor, (id)blackColor.CGColor, nil];
[myView.layer insertSublayer:layer atIndex:0];
Where layer is the layer of your view.
You can simply use a semi transparent png as a background to get the effect like this. Make sure you set the UIView's opaque to NO and you will be fine.
There is no magic needed for this effect to be achieved.
You should do it like Apple does it. UIImageViews with small, stretched images.
This view (the bottom-half square that includes the icons) uses an image that stretches and produces this effect.
You should follow this method too. Your views will be very light and it will just cost you a few tests in Photoshop to achieve the correct effect.
As I have noticed, Apple never uses gradient layers on the iPhone. It must be significantly more GPU consuming because it would have saved them a lot of images...
Here's a similar image to test with.
Hope it helps.
You just need to set the view's background color's alpha value to your desired value.
See attached zip code. Go to AlphaViewController's nib file and see it there
I have only set the alpha value for the subview to 70%. You can do it according to your requirements.
In Case if anyone need Swift 3.X
func addLinearGradientToView(view: UIView, colour: UIColor, transparntToOpaque: Bool, vertical: Bool)
{
let gradient = CAGradientLayer()
let gradientFrame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
gradient.frame = gradientFrame
var colours = [
colour.cgColor,
colour.withAlphaComponent(0.9).cgColor,
colour.withAlphaComponent(0.8).cgColor,
colour.withAlphaComponent(0.7).cgColor,
colour.withAlphaComponent(0.6).cgColor,
colour.withAlphaComponent(0.5).cgColor,
colour.withAlphaComponent(0.4).cgColor,
colour.withAlphaComponent(0.3).cgColor,
colour.withAlphaComponent(0.2).cgColor,
colour.withAlphaComponent(0.1).cgColor,
UIColor.clear.cgColor
]
if transparntToOpaque == true
{
colours = colours.reversed()
}
if vertical == true
{
gradient.startPoint = CGPoint(x: 0, y: 0.5)
gradient.endPoint = CGPoint(x: 0, y: 0.5)
}
gradient.colors = colours
view.layer.insertSublayer(gradient, at: 0)
}
Other way in Swift 3.x
let gradient = CAGradientLayer()
gradient.frame = view.bounds
gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
view.layer.insertSublayer(gradient, at: 0)

adding black overlay with 0.3 opacity over UIImageView

I have a UIImageView and I wanted to add a black overlay on top of it. What is the best way of doing this without having to override drawRect? I was thinking of adding a CALayer on top of it. But unsure how to get a black CALayer with a .3 alpha.
Something like this?
UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, myImageView.frame.size.width, myImageView.frame.size.height / 2)];
[overlay setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]];
[myImageView addSubview:overlay];
Thanks to Mick MacCallum
Swift 3 Version
let overlay: UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell.imageView.frame.size.width, height: cell.imageView.frame.size.height))
overlay.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.1)
cell.imageView.addSubview(overlay)
I have used for Swift 2.2
let overlay: UIView = UIView(frame: CGRectMake(0, 0, cell.imageView.frame.size.width, cell.imageView.frame.size.height))
overlay.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.1)
cell.imageView.addSubview(overlay)
The MDT answer is correct. This is just another way to use a CAGradientLayer beside of UIView . I think it will make what you want with more graphical options.
first you should add
#import <QuartzCore/QuartzCore.h>
to your ViewController.m and any place that you want to add this overlay to your UIImage use:
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = myImageView.layer.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:
(id)[UIColor colorWithWhite:0.9f alpha:0.7f].CGColor,
(id)[UIColor colorWithWhite:0.0f alpha:0.3f].CGColor,
nil];
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.5f],
nil];
//If you want to have a border for this layer also
gradientLayer.borderColor = [UIColor colorWithWhite:1.0f alpha:1.0f].CGColor;
gradientLayer.borderWidth = 1;
[myImageView.layer addSublayer:gradientLayer];
I hope this will help you make it
This is similar to MDT's answer except using CALayer properties:
UIView *blackOverlay = [[UIView alloc] initWithFrame: imageView.frame];
blackOverlay.layer.backgroundColor = [[UIColor blackColor] CGColor];
blackOverlay.layer.opacity = 0.3f;
[self.view addSubview: blackOverlay];
Did you think about adding a UIView with black backgroundColor and 0.3 alpha as a subview to the image view?
Swift 5 Version:
func addOverlay(on view: UIView) {
let overlay: UIView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height))
overlay.backgroundColor = UIColor.gray
view.addSubview(overlay)
}

iPhone iOS how to add linear gradient to a UIButton under the button's text or image?

I'm working on creating fancy looking UIbuttons by adding linear gradient to the button. However I'm not sure at which index I need to add the gradient. The code that I have currently places the gradient over the image/text.
How can I insert a sublayer to a UIButton under the text/image sublayer? It is important for me to keep the text and the image of a button visible!
+(void)addLinearGradientToView:(UIView*)view TopColor:(UIColor*)topColor BottomColor:(UIColor*)bottomColor
{
for(CALayer* layer in view.layer.sublayers)
{
if ([layer isKindOfClass:[CAGradientLayer class]])
{
[layer removeFromSuperlayer];
}
}
CAGradientLayer* gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5, 0);
gradientLayer.endPoint = CGPointMake(0.5,1);
gradientLayer.frame = view.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[topColor CGColor], (id)[bottomColor CGColor], nil];
// [view.layer addSublayer:gradientLayer];
if(view.layer.sublayers.count>0)
{
[view.layer insertSublayer:gradientLayer atIndex:view.layer.sublayers.count-2];
}else {
[view.layer addSublayer:gradientLayer];
}
}
Add it to the layer of your custom button:
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = customButton.layer.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:
(id)[UIColor colorWithWhite:1.0f alpha:0.1f].CGColor,
(id)[UIColor colorWithWhite:0.4f alpha:0.5f].CGColor,
nil];
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:1.0f],
nil];
gradientLayer.cornerRadius = customButton.layer.cornerRadius;
[customButton.layer addSublayer:gradientLayer];
where customButton is your custom UIButton.
For what you are trying to achieve, always insert at index 0.
I wrote an article about this sort of thing recently that you may find interesting.
Swift 4
#IBOutlet weak var gButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let topGradientColor = UIColor.red
let bottomGradientColor = UIColor.yellow
let gradientLayer = CAGradientLayer()
gradientLayer.frame = gButton.bounds
gradientLayer.colors = [topGradientColor.cgColor, bottomGradientColor.cgColor]
//Vertical
//gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
//gradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
//Horizontal
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
gButton.layer.insertSublayer(gradientLayer, at: 0)
}
Here is the code to achieve this
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = <#View Variable Name#>.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)([UIColor colorWithRed:0.337 green:0.596 blue:1.000 alpha:1.000].CGColor),(id)([UIColor colorWithRed:0.757 green:0.459 blue:1.000 alpha:1.000].CGColor),(id)([UIColor colorWithRed:0.310 green:0.835 blue:1.000 alpha:1.000].CGColor),nil];
gradient.startPoint = CGPointMake(0.5,0.0);
gradient.endPoint = CGPointMake(0.5,1.0);
[<#View Variable name#>.layer insertSublayer:gradient atIndex:0];
I got this tool that makes it easy to select your colors and automatically output the code for the gradient. Very handy I use it everyday
itunes.apple.com/gb/app/gradient-creator/id1031070259?mt=12

CAGradientLayer and scrollViewTexturedBackgroundColor

I'm trying to use CAGradientLayer to fade foreground controls against the background textured view.
So in a nutshell, I have a view with the bg color as scrollViewTexturedBackgroundColor. I have a view on top of that, whose contents I'd like to fade at the border into the background view's color.
CAGradientLayer* gradient = [CAGradientLayer layer];
gradient.frame = self->scrollableCanvas.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor scrollViewTexturedBackgroundColor] CGColor], (id)[[UIColor scrollViewTexturedBackgroundColor] CGColor], nil];
[gradient setStartPoint:CGPointMake(0.90, 1)];
[gradient setEndPoint:CGPointMake(1, 1)];
[[self->scrollableCanvas layer] addSublayer:gradient];
[[self->scrollableCanvas layer] setMasksToBounds:YES];
Unfortunately, CAGradientLayer doesn't seem to support UIColors as pattern images.
any ideas how I can achieve a simple border fade effect for the subview?
thanks
You can use a little trick:
//create normal UIImageView
UIImageView* iv = [[[UIImageView alloc] initWithImage: [UIImage imageNamed :#"bg_png.png"]] autorelease];
[superview addSubview: iv];
//draw gradient on top
UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite: 1.0 alpha: 0.0] CGColor], (id)[[UIColor colorWithWhite: 1.0 alpha: 1.0] CGColor], nil];
[view.layer insertSublayer:gradient atIndex:0];
[superview addSubview: view];
I made a category on UILabel that adds gradient at the end of the label using Max's answer.
If you need, here it is:
#import "UILabel+GradientEnding.h"
#implementation UILabel (GradientEnding)
- (void)addGradientEnding
{
//draw gradient on top
UIView *gradientAlphaView = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width - 80.0, 0, 80.0, self.frame.size.height)];
UIColor *startColor = RGBA(0xf7f7f7, 0);
UIColor *endColor = RGBA(0xf7f7f7, 1);
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = gradientAlphaView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[startColor CGColor], (id)[endColor CGColor], nil];
gradient.startPoint = CGPointMake(0, 0.5);
gradient.endPoint = CGPointMake(1.0, 0.5);
[gradientAlphaView.layer insertSublayer:gradient atIndex:0];
[self addSubview:gradientAlphaView];
}
#end
But you should use your own colors. And use this define:
#define RGBA(rgbValue, opacity) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:opacity]