I have a custom UIButton with transparent background and white title.
I'm looking for a simple solution to invert it on highlight (white background and transparent title) as it is achieved on system UISegmentedControl.
Is there simpler solution than inverting alpha on snapshot used as a CALayer mask?
If not, could you tell how can I invert CALayer alpha?
You can draw the text on a CGContext using Destination Out as blend mode.
This code seems to work:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor greenColor];
UIFont* font = [UIFont fontWithName:#"Helvetica-Bold" size:18];
NSString* buttonText = #"BUTTON";
CGSize buttonSize = CGSizeMake(200, 50);
NSDictionary* textAttributes = #{NSFontAttributeName:font};
CGSize textSize = [buttonText sizeWithAttributes:textAttributes];
UIGraphicsBeginImageContextWithOptions(buttonSize, NO, [[UIScreen mainScreen] scale]);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
CGContextAddPath(ctx, path.CGPath);
CGContextFillPath(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
CGPoint center = CGPointMake(buttonSize.width/2-textSize.width/2, buttonSize.height/2-textSize.height/2);
[#"BUTTON" drawAtPoint:center withAttributes:textAttributes];
UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView* imgView = [[UIImageView alloc] initWithImage:viewImage];
[self.view addSubview:imgView];
}
By the way, if you want to set the UIImage in a UIButton instead of just adding it to a view:
UIButton* boton = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, viewImage.size.width, viewImage.size.height)];
[boton setBackgroundColor:[UIColor clearColor]];
[boton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
boton.titleLabel.font = font;
[boton setTitle:buttonText forState:UIControlStateNormal];
[boton setImage:viewImage forState:UIControlStateHighlighted];
[self.view addSubview:boton];
You could set
-(void)viewDidload: {
[yourButton setTitleColor:(UIColor *)color
forState:UIControlStateHighlighted];
[yourButton addTarget:self
action:#selector(changeButtonBackGroundColor:)
forControlEvents:UIControlEventTouchDown];
}
-(void)changeButtonBackGroundColor:(UIButton *)button {
[button setBackgroundColor:[UIColor yourColor]];
}
remember to change it back with events: UIControlEventTouchUpInside and UIControlEventTouchOutSide :)
Related
I've a question about UIButton in iOS.
I use Apple UIButton from library and I need that it, when is pressed become "selected" and its background is blue.
I make anything and it 's working correctly, but around the "label" of title my color is more dark.
I try to set label background to clearColor but it isn't a color of label and I don't know which button subview is.
Any idea?
I use Objective-C, but if anyone has idea about Swift I understand too.
Thanks in advance
Write this code in
viewDidLoad()
self.btnDemo.layer.borderWidth = 1.0;
self.btnDemo.layer.borderColor = [UIColor grayColor].CGColor;
[self.btnDemo setTitle:#"ESTERNO" forState:UIControlStateNormal];
[self.btnDemo setTitle:#"ES" forState:UIControlStateHighlighted];
[self.btnDemo setBackgroundImage:[self imageWithColor:[UIColor clearColor]] forState:UIControlStateNormal];
[self.btnDemo setBackgroundImage:[self imageWithColor:[UIColor colorWithRed:0 green:0 blue:255 alpha:1.0]] forState:UIControlStateHighlighted];
[self.btnDemo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.btnDemo setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
Here btnDemo is UiButton outlet
Below method for convert Color to image
- (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
I am creating a UIButton similar to this image:
I tried it by using following code:
+(void)createShadowOnView:(UIView *)view color:(UIColor *)color width:(CGFloat)width height:(CGFloat)height shadowOpacity:(CGFloat)shadowOpacity andShadowRadius:(CGFloat)radius{
view.layer.masksToBounds = NO;
view.layer.shadowColor = color.CGColor;
view.layer.shadowOffset = CGSizeMake(width,height);
view.layer.shadowOpacity = shadowOpacity;
[view.layer setShadowRadius:radius];
}
I was able to achieve this:
I want shadow effect on Button to be kept only on bottom part.
How can I achieve desired effect.
Maybe you should set view's backgroundcolor, so the title has no shadow, you can set view.layer.shadowOffset to change the shadow size.
UIButton *customBTn = [UIButton buttonWithType:UIButtonTypeCustom];
customBTn.backgroundColor = [UIColor whiteColor];
customBTn.frame = CGRectMake(100, 100, 200, 50);
[customBTn setTitle:#"Sign Up" forState:UIControlStateNormal];
[customBTn setTitleColor:[UIColor colorWithRed:1/255.0 green:168/255.0 blue:244/255.0 alpha:1.0] forState:UIControlStateNormal];
customBTn.layer.borderColor = [UIColor colorWithRed:1/255.0 green:168/255.0 blue:244/255.0 alpha:1.0].CGColor;
customBTn.layer.borderWidth = 2;
customBTn.layer.cornerRadius = 25;
customBTn.layer.shadowColor = [UIColor lightGrayColor].CGColor;
customBTn.layer.shadowOffset = CGSizeMake(0,8);
customBTn.layer.shadowOpacity = 0.9;
[self.view addSubview:customBTn];
Output :-
Only issue with your code is you missed to set background colour for your sign up button. Use this code,
self.signUpButton.backgroundColor = [UIColor whiteColor];
[UIView createShadowOnView:self.signUpButton color:[UIColor lightGrayColor] width:0 height:2 shadowOpacity:0.3 andShadowRadius:0];
Preview:
Code:
UIButton *buttonWithShadow = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonWithShadow setFrame:CGRectMake(10.0f, 10.0f, 300.0f, 50.0f)];
[buttonWithShadow setTitle:#"SIGN UP" forState:UIControlStateNormal];
[buttonWithShadow setTitle:#"SIGN UP" forState:UIControlStateHighlighted];
[buttonWithShadow.titleLabel setFont:[UIFont boldSystemFontOfSize:15.0f]];
[buttonWithShadow setTitleColor:[UIColor colorWithRed:1.0f/255.0 green:168.0f/255.0 blue:244.0f/255.0 alpha:1.0f] forState:UIControlStateNormal];
[buttonWithShadow setBackgroundColor:[UIColor whiteColor]];
[buttonWithShadow.layer setBorderColor:[UIColor colorWithRed:1.0f/255.0 green:168.0f/255.0 blue:244.0f/255.0 alpha:1.0f].CGColor];
[buttonWithShadow.layer setBorderWidth:2.0f];
[buttonWithShadow.layer setCornerRadius:(buttonWithShadow.frame.size.height / 2.0f)];
[buttonWithShadow.layer setShadowColor:[UIColor lightGrayColor].CGColor];
[buttonWithShadow.layer setShadowOpacity:0.3f];
[buttonWithShadow.layer setShadowRadius:0.0f];
[buttonWithShadow.layer setShadowOffset:CGSizeMake(0.0f,2.0f)];
[buttonWithShadow.layer setMasksToBounds:NO];
[self.view addSubview:buttonWithShadow];
I have a set of UIButtons with background colors. when the user taps one, I want only the button's text to have a shadow all around it (to show that it has been selected). However, when I add the shadow, the shadow appears over the whole button (background and all), and not just the text. Is there an easier workaround to this than just adding a UILabel over a blank button?
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
...
[button setBackgroundColor:[UIColor blueColor]];
[button.layer setShadowRadius:8.0];
[button.layer setShadowColor:[[UIColor orangeColor] CGColor]];
[button.layer setShadowOpacity:0];
...
Here is the simple way to add shadow to the button title with shadow radius property available in Objective-C:
#import <QuartzCore/QuartzCore.h>
button.titleLabel.layer.shadowOffset = CGSizeMake(2.0, 2.0);
button.titleLabel.layer.shadowColor = [UIColor colorWithWhite:0.1 alpha:0.7].CGColor;
button.titleLabel.layer.shadowRadius = 2.0;
button.titleLabel.layer.shadowOpacity = 1.0;
button.titleLabel.layer.masksToBounds = NO;
Swift ..
Say you override the UIButton class ..
titleLabel!.layer.shadowColor = UIColor.black.cgColor
titleLabel!.layer.shadowOffset = CGSize(width: -0.5, height: 0.5)
titleLabel!.layer.shadowOpacity = 1.0
titleLabel!.layer.shadowRadius = 0
titleLabel!.layer.masksToBounds = false
You need to use setTitleShadowColor: forState: and shadowOffset property of UIButton.
below code will add shadow only to button label whenever user tap on button.
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setBackgroundColor:[UIColor blueColor]];
button.frame = CGRectMake(50, 70, 200, 100);
[button setTitle:#"Test Button" forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont systemFontOfSize:45]];
[button setTitleShadowColor:[UIColor redColor] forState:UIControlStateHighlighted];
[button.titleLabel setShadowOffset:CGSizeMake(2.0, 2.0)];
Hope this will help.
Just set the shadow on the titleLabel property of the UIButton rather than what you're doing now.
eg
button.titleLabel.shadowColor = ((selectionState) ?[UIColor orangeColor] : [UIColor clearColor] );
button.titleLabel.shadowOffset = CGSizeMake (1.5,1.5);
For 2018
This does not work. Use the answer of #Userich
One way to do this is to use attributed strings for the normal and highlighted titles. You can create an NSShadow object, and assign that as the value for the NSShadowAttributeName. This gives you control over the properties of the shadow. To keep the title from dimming, you should set the button type to Custom instead of System.
- (void)viewDidLoad {
[super viewDidLoad];
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor darkGrayColor];
shadow.shadowOffset = CGSizeMake(2, 2);
shadow.shadowBlurRadius = 2;
NSString *titleString = #"Title";
NSAttributedString *normalTitle = [[NSAttributedString alloc] initWithString:titleString];
NSAttributedString *highlightedTitle = [[NSAttributedString alloc] initWithString:titleString attributes:#{NSShadowAttributeName:shadow}];
[self.button setAttributedTitle:normalTitle forState:UIControlStateNormal];
[self.button setAttributedTitle:highlightedTitle forState:UIControlStateHighlighted];
}
I have a subclassed UIButton
- (void)configureButton
{
self.titleLabel.font = [UIFont systemFontOfSize:18.0f];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
CALayer *border = [CALayer layer];
border.backgroundColor = [UIColor whiteColor].CGColor;
border.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width, 1.0);
[self.layer addSublayer:border];
}
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
// remove all layers ?
if (selected) {
CALayer *border = [CALayer layer];
border.backgroundColor = [UIColor whiteColor].CGColor;
border.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width,3.0);
[self.layer addSublayer:border];
self.titleLabel.font = [UIFont boldSystemFontOfSize:18.0f];
} else {
CALayer *border = [CALayer layer];
border.backgroundColor = [UIColor whiteColor].CGColor;
border.frame = CGRectMake(0, self.frame.size.height, self.frame.size.width,1.0);
[self.layer addSublayer:border];
self.titleLabel.font = [UIFont systemFontOfSize:18.0f];
}
}
The default state of the button has a 1.0 bottom border. When it is selected, the border should become 3.0. How can I clear the previously added layer and re add a 1.0 border when a user toggles a button?
I believe there is an easier way to do what you need. If you subclass the UIButton just because you just want to have different types button border, you can try a different way but a lot easier.
Use 2 different button background image, one with border 1 and another with border 3.
[self.button setBackgroundImage:[UIImage imageNamed:#"ImageWithBorder1"] forState:UIControlStateNormal];
[self.button setBackgroundImage:[UIImage imageNamed:#"ImageWithBorder3"] forState:UIControlStateHighlighted];
[self.button setBackgroundImage:[UIImage imageNamed:#"ImageWithBorder3"] forState:UIControlStateSelected];
With an additional button image, it might just take extra 10 kb on your project.
I am having some trouble setting the correct location of the image for a UIImageView, which I am adding as a subview to a UIButton. I start by creating the button and adding some sublayers:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:bounds];
//add gradient background
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = button.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[UIColor colorWithRed:.5 green:.5 blue:.5 alpha:1.0].CGColor, (id)[[UIColor blackColor] CGColor], nil];
[button.layer insertSublayer:gradient atIndex:0];
//set green background
CALayer *layer = [CALayer layer];
layer.frame = CGRectInset(button.bounds, 5, 5);
layer.backgroundColor = [UIColor colorWithRed:.55 green:.8 blue:.5 alpha:1.0].CGColor;
[button.layer insertSublayer:layer above:gradient];
I then use two methods to set the image. The first (which I use if no image is saved) uses an image resource that is scaled to be the right size, and is part of the app bundle. I set this with the following code:
UIImageView *v = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"profile.png"]];
[v setBounds:CGRectInset(button.bounds, 8, 8)];
[button addSubview:v];
The trouble comes from when I use an image taken through the camera, and saved to the file system. I am setting this to the background using the following code:
//path is an NSString set the the documents location of the image.
UIImageView *v = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:path]];
[v setBounds:CGRectInset(button.bounds, 8, 8)];
[v setContentMode:UIViewContentModeScaleToFill];
[button addSubview:v];
The output to the screen now shows the image way offset from where it should be:
What am I doing wrong? How do I correctly scale/fit the image in its parent view? I have tried simply setting the button image, but nothing appeared (perhaps the image was behind the sublayers?).
Use -setFrame method to set the frame of imageview instead of bounds
[v setFrame:CGRectInset(button.bounds, 8, 8)];
Thus the code become
UIImageView *v = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:path]];
[v setFrame:CGRectInset(button.bounds, 8, 8)];
[v setContentMode:UIViewContentModeScaleToFill];
[button addSubview:v];