I've created a CAGradientLayer, which I'd like to add as a sublayer to a UIView. I can add it to self.view.layer with no problems, but cannot for the life of me get it to appear when added to the UIView.
Here's the simplified code.
- (CAGradientLayer*) makeGradient
{
//method returns the gradient layer
CAGradientLayer *gradeLayer = [CAGradientLayer layer];
gradeLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
gradeLayer.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.2], [NSNumber numberWithFloat:0.5], nil];
return gradeLayer;
}
-(void)addGradient
{
//method creates UIView, then creates Gradient, and tries to add it to the UIView
UIView *myView = [[UIView alloc] initWithFrame:self.view.frame];
myView.backgroundColor = [UIColor clearColor];
myView.opaque = NO;
CAGradientLayer *bg = [self makeGradient];
CGRect myRect = myView.bounds;
myRect.size.height = myRect.size.height * 5;
myRect.origin.y = myView.bounds.size.height-myRect.size.height;
bg.frame = myRect;
//Adding gradient to self.view.layer works like a charm...
//[self.view.layer insertSublayer:bg atIndex:0];
//...however, adding it to my custom view doesn't work at all.
[myView.layer insertSublayer:bg atIndex:0];
}
What am I missing? Thanks in advance for any insight.
Your problem is that you don't seem to be setting a frame on the sub layer. Instead a cleaner option is to subclass UIView and use layerClass.
CustomGradientView.h
// For CALayers, make sure you also add the QuartzCore framework
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#interface CustomGradientView : UIView
// Redeclare the layer property but as the new CALayer class so it can receive the correct
// messages without compiler warnings.
#property (nonatomic, strong, readonly) CAGradientLayer *layer;
#end
CustomGradientView.m
#import "CustomGradientView.h"
#interface CustomGradientView ()
#end
#implementation CustomGradientView
+(Class)layerClass
{
return [CAGradientLayer class];
}
-(instancetype)init
{
self = [super init];
if (self) {
[self customInit];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder];
if (self) {
[self customInit];
}
return self;
}
-(void)customInit
{
self.layer.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
self.layer.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.2], [NSNumber numberWithFloat:0.5], nil];
}
#end
Related
I'd like to be able to customize any buttons I'll create within a specific style of my app. I was trying to create a new class which will consist of all my settings, so every time I add a new button I can use methods of the class to customize the new button.
I'm a very new to the iOS programming so I quess I might've been doing something wrong, but that's what I've got so far:
I created the class with settings
#import "CustomButton.h"
#implementation CustomButton
-(UIButton *) setButtonWithType{
self.layer.cornerRadius = 25;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(1.5f, 1.5f);
self.layer.shadowOpacity = 1.0f;
self.layer.shadowRadius = 0.0f;
self.layer.masksToBounds = NO;
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.bounds;
gradient.startPoint = CGPointMake(0.5, 0.5);
gradient.endPoint = CGPointMake(0.0, 0.5);
gradient.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,(id)[UIColor colorWithRed:230/255.0 green:230/255.0 blue:230/255.0 alpha:1.0].CGColor, nil];
gradient.cornerRadius = self.layer.cornerRadius;
[self.layer insertSublayer:gradient atIndex:0];
return self;
}
#end
ViewController.h
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *button;
#end
ViewController.m
#import "ViewController.h"
#import "CustomButton.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CustomButton *btn = [[CustomButton alloc] init];
self.button = [btn setButtonWithType];
//rest of the code
Any ideas how to make it works?
Or do I need to use a very different approach?
Thank you!!
You may find success doing this as a Category (lots of examples out there)...
UIButton+ShadowRoundedGradient.h
#import <UIKit/UIKit.h>
#interface UIButton (ShadowRoundedGradient)
- (void) makeMe;
#end
UIButton+ShadowRoundedGradient.m
#import "UIButton+ShadowRoundedGradient.h"
#implementation UIButton (ShadowRoundedGradient)
- (void) makeMe {
self.layer.cornerRadius = 25;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(1.5f, 1.5f);
self.layer.shadowOpacity = 1.0f;
self.layer.shadowRadius = 0.0f;
self.layer.masksToBounds = NO;
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.bounds;
gradient.startPoint = CGPointMake(0.5, 0.5);
gradient.endPoint = CGPointMake(0.0, 0.5);
gradient.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,(id)[UIColor colorWithRed:230/255.0 green:230/255.0 blue:230/255.0 alpha:1.0].CGColor, nil];
gradient.cornerRadius = self.layer.cornerRadius;
[self.layer insertSublayer:gradient atIndex:0];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
#property (weak, nonatomic) IBOutlet UIButton *button;
}
#end
ViewController.m
#import "ViewController.h"
#import "UIButton+ShadowRoundedGradient"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.button makeMe];
//rest of the code
}
I am currently using the following method to set the background color of my view
//Set the background color
CAGradientLayer *bgLayer = [BackgroundLayer blueGradient]; <---Calls method below
bgLayer.frame = self.view.bounds;
//self.view.layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer insertSublayer:bgLayer atIndex:0];
This is how it obtains the gradient color - this is the method is called above
#implementation BackgroundLayer
//Blue gradient background
+ (CAGradientLayer*) blueGradient {
UIColor *colorOne = [UIColor colorWithRed:(120/255.0) green:(135/255.0) blue:(150/255.0) alpha:1.0];
UIColor *colorTwo = [UIColor colorWithRed:(57/255.0) green:(79/255.0) blue:(96/255.0) alpha:1.0];
NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil];
NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
NSNumber *stopTwo = [NSNumber numberWithFloat:1.0];
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];
CAGradientLayer *headerLayer = [CAGradientLayer layer];
headerLayer.colors = colors;
headerLayer.locations = locations;
return headerLayer;
}
#end
Now in the portrait mode the background appears fine. However in Landscape mode it only covers half the screen and the other half is white. Why is that ? And how can I fix it. I tried the following for changing the color
self.view.layer.backgroundColor = [UIColor redColor].CGColor;
The above works fine both in landscape an portrait mode however its not a gradient. Any ideas on how I can make the gradient work ?
Easy way:
Just Add this to your viewcontroller
-(void)viewDidLayoutSubviews{
self.bgLayer.frame = self.view.bounds;
}
Better way:
As hereDescribe, you can do it in this way.I test it with My Xcode,it works fine.
Define a background view to manage size
.h file
#import <UIKit/UIKit.h>
#interface BackgrundView : UIView
#end
.m file
#import "BackgrundView.h"
#interface BackgrundView()
#end
#implementation BackgrundView
+(Class)layerClass{
return [CAGradientLayer class];
}
#end
2 Set up what you want
#import "ViewController.h"
#import "BackgrundView.h"
#interface ViewController ()
#property BackgrundView * backgroundview;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.backgroundview = [[BackgrundView alloc] initWithFrame:self.view.frame];
self.backgroundview.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.backgroundview];
UIColor *colorOne = [UIColor colorWithRed:(120/255.0) green:(135/255.0) blue:(150/255.0) alpha:1.0];
UIColor *colorTwo = [UIColor colorWithRed:(57/255.0) green:(79/255.0) blue:(96/255.0) alpha:1.0];
NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil];
NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
NSNumber *stopTwo = [NSNumber numberWithFloat:1.0];
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];
CAGradientLayer * graintLayer = (CAGradientLayer *)self.backgroundview.layer;
graintLayer.colors = colors;
graintLayer.locations = locations;
}
Correct line of code is: self.view.backgroundColor = [UIColor redColor];
Are you updating the frame of the Background layer when the device rotates to Landscape?
Apparently your problem can be solved from the answer in this question here
You need to add a new gradient when your device rotates.
- (void)viewDidLayoutSubviews // called when device rotates
{
[self.bgLayer removeFromSuperlayer]; // you need to keep reference so you can remove the old layer
self.bgLayer = [BackgroundLayer blueGradient]; <---Calls method below
self.bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:self.bgLayer atIndex:0];
}
look #WenchenHuang answer, its better than my approach.
I created my own class derived from UIButton with .h file:
#interface MenuButton : UIButton
- (void)changeBackground;
#end
In implementation I tried to add some methods for changing background but without success so far:
#import "MenuButton.h"
#import "GradientLayers.h"
#implementation MenuButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder;
{
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit;
{
// Gradient background
CAGradientLayer *gradient = [GradientLayers darkBlueBackground];
gradient.frame = [self layer].bounds;
// Insert background
[[self layer] insertSublayer:gradient atIndex:0];
[[self layer] setCornerRadius:10.0f];
[[self layer] setMasksToBounds:YES];
[[self layer] setBorderWidth:2];
[[self layer] setBorderColor:[[UIColor blackColor] CGColor]];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// handle touch
[super touchesEnded:touches withEvent:event];
if ([self state] != UIControlStateSelected)
{
CAGradientLayer *gradient = [GradientLayers blackBackground];
gradient.frame = [self layer].bounds;
[[self layer] insertSublayer:gradient atIndex:0];
}
else
{
CAGradientLayer *gradient = [GradientLayers darkBlueBackground];
gradient.frame = [self layer].bounds;
[[self layer] insertSublayer:gradient atIndex:0];
}
}
- (void)changeBackground
{
CAGradientLayer *gradient = [[[self layer] sublayers] firstObject];
gradient = [GradientLayers blackBackground];
[[self layer] insertSublayer:gradient atIndex:0];
[self setNeedsDisplay];
}
#end
Part of GradientLayer.m file:
#import "GradientLayers.h"
#implementation GradientLayers
+ (CAGradientLayer*) blackBackground {
// similar to darkBlueBackground
}
+ (CAGradientLayer*) darkBlueBackground {
// Create colors
UIColor *darkOp = [UIColor colorWithRed:0.039f green:0.106f blue:0.278f alpha:1.0];
UIColor *lightOp = [UIColor colorWithRed:0.133f green:0.267f blue:0.65f alpha:1.0];
// Create gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
// Set colors
gradient.colors = [NSArray arrayWithObjects:
(id)lightOp.CGColor,
(id)darkOp.CGColor,
nil];
// Shadow
gradient.shadowOffset = CGSizeMake(3.0f, 3.0f);
gradient.shadowColor = [UIColor blackColor].CGColor;
gradient.shadowOpacity = 0.6;
gradient.shadowRadius = 10;
// Other options
gradient.borderWidth = 0.5f;
gradient.borderColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0].CGColor;
gradient.cornerRadius = 10;
return gradient;
}
#end
I have my buttons with darkBlueBackground as set in commonInit. It's not a problem. But I want to change it after user taps on button and so far without luck. If I set breakpoint I am in touchesEnded or changeBackground but after execution the button has same background as before. So how can I change background to another gradient background? Thanks
Because the [self layer].sublayers array is listed in back to front order (https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instp/CALayer/sublayers), by inserting your replacement layer at index 0, you're always putting it behind the old gradient.
You should remove the old gradient layer and then add the new one.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// handle touch
[super touchesEnded:touches withEvent:event];
// Remove old gradient here
[[[[self layer] sublayers] objectAtIndex:0] removeFromSuperlayer];
if ([self state] != UIControlStateSelected)
{
CAGradientLayer *gradient = [GradientLayers blackBackground];
gradient.frame = [self layer].bounds;
[[self layer] insertSublayer:gradient atIndex:0];
}
else
{
CAGradientLayer *gradient = [GradientLayers darkBlueBackground];
gradient.frame = [self layer].bounds;
[[self layer] insertSublayer:gradient atIndex:0];
}
}
- (void)changeBackground
{
// Remove old gradient here
[[[[self layer] sublayers] objectAtIndex:0] removeFromSuperlayer];
CAGradientLayer *gradient = [[[self layer] sublayers] firstObject];
gradient = [GradientLayers blackBackground];
[[self layer] insertSublayer:gradient atIndex:0];
[self setNeedsDisplay];
}
You really should keep track of the gradient better, so you're not constantly removing and replacing it with the same gradient. Perhaps maybe just showing and hiding the selected state, which would always just sit above the unhighlighted version.
I have a view controller with a central container that gets flipped to show different views on each side. One of the views is a table view and the other is a custom view of mine. It is working perfectly as per screenshot 1.
My problem is that after I have added a subview over this viewcontroller (its a transparent UIView for showing help screen) and then remove this subview from the viewcontroller
, when I try re-flip the central view strange results occur. There still seems to be a flipping animation between the two views, but as you can see from the last 2 screenshot an extra central table view just sits there. I can't quite explain this exactly so I'm hoping a combination of the pictures, and some code will help:
MainPageVC.h
#interface MainPageVC : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
MainPageVC.m
#interface MainPageVC ()
#property (nonatomic, strong) NSArray *dataArr;
#property (nonatomic, weak) IBOutlet UIView *flipContainerView;
#property (nonatomic, strong) UIView *detailFlipView;
#property (nonatomic, strong) UITableView *listFlipView;
#property (nonatomic) BOOL isTransitioning;
#property (nonatomic) BOOL isFlipped;
#end
#implementation MainPageVC
#synthesize dataArr = _dataArr;
#synthesize flipContainerView = _flipContainerView;
#synthesize detailFlipView = _detailFlipView;
#synthesize listFlipView = _listFlipView;
#synthesize isTransitioning = _isTransitioning;
#synthesize isFlipped = _isFlipped;
- (void)viewDidLoad {
[super viewDidLoad];
self.dataArr = [NSArray arrayWithObjects:#"row 1", #"row 2", #"row 3", nil];;
}
- (void)viewDidLayoutSubviews {
[self setUpCustomViews];
}
- (void)setUpCustomViews {
self.isFlipped = NO;
self.isTransitioning = NO;
CGRect frame = CGRectMake(0, 0, self.flipContainerView.frame.size.width, self.flipContainerView.frame.size.height);
self.detailFlipView = [[UIView alloc] initWithFrame:frame];
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,50)];
[self.detailFlipView addSubview:customView];
self.listFlipView = [[UITableView alloc] initWithFrame:frame];
self.listFlipView.delegate = self;
self.listFlipView.dataSource = self;
UIColor *backgroundColour = [UIColor whiteColor];
CGFloat cornerRadius = 15.0f;
CGFloat borderWidth = 1.5f;
UIColor *borderColour = [UIColor colorWithRed:49.0/255.0f green:49.0/255.0f blue:49.0/255.0f alpha:1.0f];
self.detailFlipView.backgroundColor = backgroundColour;
self.listFlipView.backgroundColor = backgroundColour;
self.detailFlipView.layer.cornerRadius = cornerRadius;
self.listFlipView.layer.cornerRadius = cornerRadius;
self.detailFlipView.layer.borderWidth = borderWidth;
self.listFlipView.layer.borderWidth = borderWidth;
self.detailFlipView.layer.borderColor = [borderColour CGColor];
self.listFlipView.layer.borderColor = [borderColour CGColor];
self.detailFlipView.layer.doubleSided = NO;
self.listFlipView.layer.doubleSided = NO;
self.listFlipView.layer.masksToBounds = YES;
self.detailFlipView.layer.masksToBounds = YES;
[self.flipContainerView addSubview:self.detailFlipView];
[self.flipContainerView addSubview:self.listFlipView];
}
- (IBAction)changeViewTapped:(UIControl *)sender {
if (self.isTransitioning) return;
CALayer *top = self.listFlipView.layer;
CALayer *bottom = self.detailFlipView.layer;
if (self.isFlipped) {
top = self.detailFlipView.layer;
bottom = self.listFlipView.layer;
}
CAAnimation *topAnimation = [self flipAnimationWithDuration:0.6f forLayerBeginningOnTop:YES scaleFactor:1.2f];
CAAnimation *bottomAnimation = [self flipAnimationWithDuration:0.6f forLayerBeginningOnTop:NO scaleFactor:1.2f];
CGFloat zDistance = 1000.0f;
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1. / zDistance;
top.transform = perspective;
bottom.transform = perspective;
topAnimation.delegate = self;
[CATransaction begin];
[top addAnimation:topAnimation forKey:#"flip"];
[bottom addAnimation:bottomAnimation forKey:#"flip"];
CABasicAnimation *colorAnimation = [CABasicAnimation animationWithKeyPath:#"backgroundColor"];
colorAnimation.toValue = (id)[UIColor colorWithRed:27.0/255.0f green:47.0/255.0f blue:87.0/255.0f alpha:1.0f].CGColor;
[self.bannerButtonImageView.layer addAnimation:colorAnimation forKey:#"colorAnimation"];
[CATransaction commit];
}
-(CAAnimation *)flipAnimationWithDuration:(NSTimeInterval)aDuration forLayerBeginningOnTop:(BOOL)beginsOnTop scaleFactor:(CGFloat)scaleFactor {
self.isTransitioning = YES;
CABasicAnimation *flipAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
CGFloat startValue = beginsOnTop ? 0.0f : M_PI;
CGFloat endValue = beginsOnTop ? -M_PI : 0.0f;
flipAnimation.fromValue = [NSNumber numberWithDouble:startValue];
flipAnimation.toValue = [NSNumber numberWithDouble:endValue];
CABasicAnimation *shrinkAnimation = nil;
if (scaleFactor != 1.0f ) {
shrinkAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
shrinkAnimation.toValue = [NSNumber numberWithFloat:scaleFactor];
shrinkAnimation.duration = aDuration * 0.5;
shrinkAnimation.autoreverses = YES;
}
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = [NSArray arrayWithObjects:flipAnimation, shrinkAnimation, nil];
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animationGroup.duration = aDuration;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = NO;
return animationGroup;
}
-(void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
self.isFlipped = !self.isFlipped;
self.isTransitioning = NO;
}
...USUAL UITABLEVIEW METHODS
- (void)showHelpScreen {
CustomHelp *helpView = [[CustomHelp alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:helpView];
}
#end
CustomHelp.h
#interface CustomHelp : UIView
#end
CustomHelp.m
#implementation CustomHelp
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 50, 100)];
test.backgroundColor = [UIColor redColor];
[self addSubview:test];
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
}
return self;
}
- (void)handleSingleTap {
[UIView animateWithDuration:0.5
animations:^{ self.alpha = 0.0;}
completion:^(BOOL finished){
[self removeFromSuperview];
}];
}
#end
Adding comment as answer.
My only suggestion would be in the setUpCustomViews function to add in an if(!self.listFlipView) and if(!self.detailFlipView) to the view creation. That function may be being called multiple times and thereby adding multiple views to your window without removing the previous one.
Hi I have made a custom button in code using corner radius CAGradientLayer and border colour in one of my view controllers like the below:
phoneButton = [CustomButton buttonWithType:UIButtonTypeCustom];
phoneButton.frame = CGRectMake(6, 363, 99, 48);
phoneButton.titleLabel.font = [UIFont fontWithName:#"Futura-Medium" size:14];
phoneButton.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:1.0];
phoneButton.titleLabel.shadowOffset = CGSizeMake(0, 1);
[phoneButton setTitle:#"Phone" forState:UIControlStateNormal];
[phoneButton addTarget:self action:#selector(phone) forControlEvents:UIControlEventTouchUpInside];
gradient = [CAGradientLayer layer];
gradient.frame = phoneButton.bounds;
gradient.cornerRadius = 8;
gradient.borderColor = [[UIColor whiteColor]CGColor];
gradient.borderWidth = 2.0;
gradient.colors = [NSArray arrayWithObjects:(id)[[sharedManager cellGradientEnd] CGColor], (id)[[sharedManager cellGradientStart] CGColor], nil];
[phoneButton.layer insertSublayer:gradient atIndex:0];
[self.view addSubview:phoneButton];
Now I would like to set the selected/highlighted color of the button on selection. How do I do this. I read make a UIbutton subclass and override setSelected but I dont have a clue how to do it. Here is customButton subclass.m
#import "CustomButton.h"
#implementation CustomButton
#synthesize sharedManager;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
sharedManager = [[MySingleton alloc]init];
}
return self;
}
-(void) setHighlighted:(BOOL)highlighted {
if(highlighted) {
NSLog(#"Highlighted");
} else {
NSLog(#"Not Highlighted");
}
[super setHighlighted:highlighted];
}
-(void) setSelected:(BOOL)selected {
if(selected) {
NSLog(#"Selected");
} else {
NSLog(#"Not Selected");
}
[super setSelected:selected];
}
#end
Or just dim the button on selection would be good? I should add that the button is not in a Xib.
I figured it out just by creating a selected Gradient and unselected Gradient state of the button in subclass.m now it is all working great!
- (CustomButton *)buttonWithType:(UIButtonType)type
{
return [self buttonWithType:UIButtonTypeCustom];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder *)coder
{
//Call the parent implementation of initWithCoder
self = [super initWithCoder:coder];
//Custom drawing methods
if (self)
{
[self drawBackgroundLayer];
[self drawHighlightBackgroundLayer];
highlightBackgroundLayer.hidden = YES;
}
return self;
}
-(void)loadSingleton{
sharedManager = [[MySingleton alloc]init];
}
- (void)layoutSubviews
{
// Set gradient frame (fill the whole button))
backgroundLayer.frame = self.bounds;
// Set inverted gradient frame
highlightBackgroundLayer.frame = self.bounds;
[super layoutSubviews];
}
- (void)drawBackgroundLayer
{
[self loadSingleton];
// Check if the property has been set already
if (!backgroundLayer)
{
backgroundLayer = [CAGradientLayer layer];
backgroundLayer.cornerRadius = 8;
backgroundLayer.borderWidth = 1.5;
backgroundLayer.borderColor = [UIColor whiteColor].CGColor;
backgroundLayer.colors = [NSArray arrayWithObjects:(id)[[sharedManager cellGradientEnd] CGColor], (id)[[sharedManager cellGradientStart] CGColor], nil];
// Add the gradient to the layer hierarchy
[self.layer insertSublayer:backgroundLayer atIndex:0];
}
}
- (void)drawHighlightBackgroundLayer
{
[self loadSingleton];
if (!highlightBackgroundLayer)
{
highlightBackgroundLayer = [CAGradientLayer layer];
highlightBackgroundLayer.cornerRadius = 8;
highlightBackgroundLayer.borderWidth = 1.5;
highlightBackgroundLayer.borderColor = [UIColor whiteColor].CGColor;
highlightBackgroundLayer.colors = [NSArray arrayWithObjects:(id)[[sharedManager cellSelectedGradientEnd] CGColor], (id)[[sharedManager cellSelectedGradientStart] CGColor], nil];
[self.layer insertSublayer:highlightBackgroundLayer atIndex:1];
}
}
and setting the selected state on or off
- (void)setHighlighted:(BOOL)highlighted
{
NSLog(#"Selected");
// Disable implicit animation
[CATransaction begin];
[CATransaction setDisableActions:YES];
// Hide/show inverted gradient
highlightBackgroundLayer.hidden = !highlighted;
[CATransaction commit];
[super setHighlighted:highlighted];
}
Have you tried invoking super and then invoking setNeedsDisplay on self?
It should cause your display functionality to be invoked at the appropriate time, and in that code you should be checking for selected/highlighted.
If I understand correctly what you are trying to do, I would suggest the following approach:
move the CAGradientLayer inside of your CustomButton implementation (so it would become a CustomGradientButton);
when you want to set the selected state for the custom button, change the CAGradientLayer gradientColors by changing their saturation and brightness.
By doing this, your button will change its appearance in the selected state.
A way to modify saturation and brightness could be through this UIColor category of mine:
#interface UIColor (LighterDarkerColor)
- (UIColor*)colorWithSaturation:(float)saturationFactor
brightness:(float)brightnessFactor;
#end
#implementation UIColor (LighterDarkerColor)
- (UIColor*)colorWithSaturation:(float)saturationFactor
brightness:(float)brightnessFactor {
float hue = 0.0;
float saturation = 0.0;
float brightness = 0.0;
float alpha = 0.0;
if ([self getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha])
return [UIColor colorWithHue:hue saturation:saturation*saturationFactor
brightness:brightness*brightnessFactor alpha:alpha];
return self;
}
#end
You could do, e.g.:
UIColor* selectedColorStart = [[sharedManager cellGradientStart] colorWithSaturation:0.65 brightness:1.2];
to get a less saturated, brighter version of your cellGradientStart color. Then in your setSelected method you would modify your CAGradientLayer:
gradient.colors = [NSArray arrayWithObjects:(id)[selectedColorEnd CGColor], (id)[selectedColorStart CGColor], nil];
This approach works for me, although you need to fine-tune your selection of saturation and brightness working for your case.