Is there a way to set UIButtons with rounded corners globally like with color below?
[[UIButton appearance] setBackgroundColor:[UIColor purpleColor]];
The list of properties that you can set using UIAppearance is found here:
What properties can I set via an UIAppearance proxy?
Unfortunately rounded corners are not something that is possible.
You could use something like beautify (https://github.com/beautify/beautify-ios) which enhances the UIKit controls to allow you to specify rounded buttons.
With beautify, the following would give you rounded buttons globally:
BYTheme *theme = [BYTheme new];
theme.buttonStyle.border = [[BYBorder alloc] initWithColor:[UIColor blackColor]
width:2.0f
radius:5.0f];
[[BYThemeManager instance] applyTheme:theme];
I've found this link. Please see if it could help.
Taming UIButton
It is using this
[[basicButton layer] setCornerRadius:18.0f];
As i mentioned in previous answer. You have to subclass UiButton for it.. :)
#import <QuartzCore/QuartzCore.h>
Add this in your header file.
then in implementation,
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 100, 100,50);
[btn setTitle:#"Hello" forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor colorWithRed:128.0/255.0f green:0.0/255.0f blue:0.0/255.0f alpha:0.7]];
btn.frame = CGRectMake(100.0, 100.0, 120.0, 50.0);//width and height should be same value
btn.clipsToBounds = YES;
btn.layer.cornerRadius = 20;//half of the width
btn.layer.borderColor=[UIColor redColor].CGColor;
btn.layer.borderWidth=2.0f;
cornerRadius will do the trick for you.. Let me know if more info needed.. :)
Edit
This cannot be achieved globally. As you used appearence, here is the list to see what you can customize with UIAppearance. what you can do is you can create a subclass of your UIButton, & there you can write implementation of setCornerRadius in initWithCoder Method.
Migrating advice for a workable solution to Swift (it's also possible using an equivalent ObjC category on UIView):
1. Add this extension https://gist.github.com/d3ce2e216884541217d0
2. Code:
let a = UIButton.appearance()
a.layerCornerRadius = 20.0
a.layerBorderColor = UIColor.redColor().CGColor
a.layerBorderWidth = 2.0
This sort of hack works because of how properties are copied. All appearance changes to things like a.layer and a.titleLabel are not propagated, but extension properties are copied.
Related
I'm creating a simple button and adding it as a subview to main view. It doesn't show up though.
This is the code for setting it up:
UIButton* contactButton = [[UIButton alloc] init];
contactButton.titleLabel.text = #"Contact Developer";
[contactButton sizeToFit];
[self.view addSubview:contactButton];
NSLog(#"X: %f || Y: %f || Width: %f || Height: %f", contactButton.frame.origin.x, contactButton.frame.origin.y, contactButton.frame.size.width, contactButton.frame.size.height);
As you may have noticed, I placed a bit of debug code at the end to see the position and dimensions of the button. They are: X: 0, Y: 0, Width: 30, Height: 34
This means it should be showing up in the upper left corner but it doesn't. Whats wrong?
One possible reason for this is that you used titleLabeldirectly. Consider using setTitle:forState: method instead.
To be sure, consider setting backgroundColor, as a debug step, to make sure it's appearing.
Edit As others suggested, try using buttonWithType: instead of [[UIButton alloc] init]. I suggest using UIButtonTypeSystem instead of UIButtonTypeCustom.
You should initialise the button using the following:
UIButton* contactButton = [UIButton buttonWithType:UIButtonTypeCustom];
Try constructing your button a different way:
UIButton* contactButton = [UIButton buttonWithType:UIButtonTypeCustom];
contactButton.backgroundColor = [UIColor redColor];
contactButton.titleLabel.text = #"Contact Developer";
[contactButton sizeToFit];
[self.view addSubview:contactButton];
Are you sure that the button it's not being shown?
I think you are setting the title of the button incorrectly and because of the fact that a default UIButton has clear background and white title, it´s not visible if your superview is white too.
Instead of setting:
contactButton.titleLabel.text = #"Contact Developer"
use:
[contactButton setTitle:#"Contact Developer" forState:UIControlStateNormal]
But you can first try to set a backgroundColor to the button, different that the superview, to see if it's added.
Hope it helps!
(Sorry for my english if i have a mistake)
It looks like this whenever off:
While I'd prefer more of a grey background. Do I really have to use a UIImageView?
Here is how I changed the fill color of my iOS7 UISwitch.
First you need to import QuartzCore.
#import <QuartzCore/QuartzCore.h>
Then set the background color and round the UISwitch's corners.
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0.0, 0.0, 51.0, 31.0)];
mySwitch.backgroundColor = [UIColor redColor];
mySwitch.layer.cornerRadius = 16.0; // you must import QuartzCore to do this.
[self addSubview:mySwitch];
This will give you a UISwitch with a custom off (background) color.
Hope this helps someone:)
You can set the setOnTintColor property of your UISwitch to the color you desire.
You can also set this for the switch in Interface Builder. Just set the background colour of the UISwitch to whatever colour you want (white, in the example below), then set a User Defined Runtime Attribute of layer.cornerRadius = 16:
There's no API support for changing the off fill color of a UISwitch.
Adjusting the tintColor will only affect the outline, and adjusting the backgroundColor will affect the whole frame, including the parts outside the rounded bounds.
You either have to place a properly shaped opaque UIView behind it or - easier - use a custom open source implementation, such as MBSwitch, which allows you to set the off fill color.
You can also use an image as background, using the [UIColor colorWithPatternImage];
mySwitch.onTintColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"toggle-bg-on"]];
mySwitch.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"toggle-bg-off"]];
Adding to Barry Wyckoff solution : set tint color also
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0.0, 0.0, 51.0, 31.0)];
mySwitch.backgroundColor = [UIColor redColor];
mySwitch.layer.cornerRadius = 16.0; // you must import QuartzCore to do this.
mySwitch.tintColor = [UIColor redColor];
[self addSubview:mySwitch];
I have uploaded a custom font and applied this font on the title of a UIbutton using the following code
videoButton.titleLabel.font = [UIFont fontWithName:#"LaurenScript" size:20];
The problem is that the title is being clipped on the top of the first letter (see photo below). I tried the same font on the UIlabel and it works fine so it is not a problem with the font. I tried also to change the rectFrame using
[videoButton.titleLabel setFrame:CGRectMake(0, 0, 300, 600)];
but that didn't do anything.
Has anybody a clue of how I can fix this problem?
Cheers
I had a similar problem, where a diaeresis got cut off on top of the titlelabel.
I made a UIButton subclass and used this code to fix the problem:
-(void)layoutSubviews
{
[super layoutSubviews];
CGRect frame = self.titleLabel.frame;
frame.size.height = self.bounds.size.height;
frame.origin.y = self.titleEdgeInsets.top;
self.titleLabel.frame = frame;
}
Select button in Interface builder and check for set a vertical alignment panel in the control section Below is example:
Not sure if this is still an issue for anyone, but I found that (with using a custom font) the above solutions did not ultimately fix the issue, especially for a custom UIButton created solely programmatically.
Here is how I managed to fix this issue, with 1 line in particular that resolved the clipping issue:
UIButton *button = [[UIButton alloc] init];
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:#"Nice!" forState:UIControlStateNormal];
[button setFont:[UIFont fontWithName:<CUSTOM FONT NAME> size:buttonWidth/3.0f]];
button = CGRectMake(0, 0, <WIDTH>, <HEIGHT>);
Here was the line that resolved the clipping:
[button setContentVerticalAlignment:UIControlContentVerticalAlignmentFill];
Hopefully this helps anyone else who still were stuck. Happy coding!
had same problem using a button with an image and text with a custom font.
Everything had to be align centered vertically. And image not stretched.
this worked out fine for me.
btn.contentVerticalAlignment = .fill
btn.contentMode = .center
btn.imageView?.contentMode = .scaleAspectFit
I try this in swift 2.1, I adapt this code from Antoine answer. This may not good code but it solve my problem for now. You should make it better for you self.
import UIKit
class CustomUIButton: UIButton {
override func layoutSubviews() {
if var titleFrame : CGRect = titleLabel?.frame{
titleFrame.size = self.bounds.size
titleFrame.origin = CGPointZero
self.titleLabel!.frame = titleFrame
self.titleLabel!.textAlignment = .Center
}
}
}
There is this (sad) solution: https://stackoverflow.com/a/10200908/352628
I have a similar problem. It seems that the titleLabel is just very uncontrollable, and to get control you need to inject a UILabel subview to the button... That makes me sad :(
UIStepper is very convenient but I want to change the appearance of it, I need to have customized icon not the plus and minus and also I want to change the color of the control. How can I achieve this? Thanks in advance!
As of iOS 6.0 you can use - (UIImage *)decrementImageForState:(UIControlState)state and - (UIImage *)incrementImageForState:(UIControlState)state to change the labels on the UIStepper control.
This works for iOS 6.0:
[_stepper setDecrementImage:[UIImage imageNamed:#"decrementIcon.png"] forState:UIControlStateNormal];
This works:
[[UIButton appearanceWhenContainedIn:[UIStepper class], nil] setBackgroundImage:[UIImage imageNamed:#"normal.png"] forState:UIControlStateNormal];
[[UIButton appearanceWhenContainedIn:[UIStepper class], nil] setBackgroundImage:[UIImage imageNamed:#"highlighted.png"] forState:UIControlStateHighlighted];
[[UIButton appearanceWhenContainedIn:[UIStepper class], nil] setBackgroundImage:[UIImage imageNamed:#"disabled.png"] forState:UIControlStateDisabled];
Not sure how future proof it is though.
You cannot presently do this. You'll have to write a custom UIControl object if you want to customize the icons.
From the UIStepper Class Reference, the only parameters you can change are
continuous property
autorepeat property
wraps property
minimumValue property
maximumValue property
stepValue property
value property
You cannot customize the icons.
However, since it is a subclass of UIView, you can try changing the backgroundColor.
Here is solution that works for me.
Platform iOS 7.1
[stepper setBackgroundImage:[UIImage new] forState:UIControlStateNormal];
[stepper setDividerImage:[UIImage new] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal];
The result is only increment, decrement images are visible.
Here's the Swift 4.0 version:
stepper.setDecrementImage(UIImage(named: "yourDecrementImage.png"), for: UIControlState.normal)
stepper.setIncrementImage(UIImage(named: "yourIncrementImage.png"), for: UIControlState.normal)
I also found that shrinking custom images to fit into the stepper buttons would blur them. This is the only extension function I found that properly shrunk the images down without blurring:
extension UIImage {
func resize(targetSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size:targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}
You can always step through the UIViews and guess, too. Anyway, this is my code, which doesn't answer the question directly, but is kind of neat.
#implementation UIStepper (Util)
- (void) fixForIos7 {
if (!IS_IOS7)
return;
for (UIView *view in self.subviews) {
view.backgroundColor = [UIColor whiteColor];
UIButton *button = (UIButton*)view;
[button setTintColor:[UIColor blackColor]];
}
}
#end
This gist I wrote shows creating a StepperControl as a subclass and set custom style of plus/minus.
P.S I have added a label image in the middle as the divider image.
func image(fromView view: UIView) -> UIImage
In regard your question, you can remove the logic for the label and instead just set blank UIImage() for the divider image.
StepperControl.swift
firstButton is a UIButton of type Custom. I'm programmatically putting three of them across each cell of a table, thusly:
[firstButton setImage:markImage forState:UIControlStateNormal];
[firstButton setContentMode:UIViewContentModeScaleAspectFit];
[cell.contentView addSubview:firstButton];
Elsewhere, I'm telling it to clipToBounds. What I get is a crop of the center square of the image, rather than an aspect-scaled rendering of it. I've tried this lots of ways, including setting the mode property on firstButton.imageView, which also doesn't seem to work.
I had the same problem. I see this question is a little old, but I want to provide a clear and correct answer to save other folks (like me) some time when it pops up in their search results.
It took me a bit of searching and experimenting, but I found the solution. Simply set the ContentMode of the "hidden" ImageView that is inside the UIButton.
[[firstButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[firstButton setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
Perhaps that's what Dan Ray was alluding to in his accepted answer, but I suspect not.
If you're dealing with the UIButton's image (as opposed to it's backgroundImage), setting the contentMode on the UIButton itself or on its imageView has no effect (despite what other answers say).
Alternatively do this instead:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
self.button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
Or size your image accordingly.
OR just use a UIImageView (which properly respects contentMode) with a UITapGestureRecognizer attached to it, or a transparent UIButton on top of it.
Rather than setting the contentMode on the button itself, you'll want to set contentHorizontalAlignment and contentVerticalAlignment properties and (crucially) the contentMode for the button's imageView for any kind of aspect fill or fit:
button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .scaleAspectFit
You can also do other things like aligning the button's image to the top. If you don't need an aspect fill or fit, you just can set the alignment by itself:
button.contentVerticalAlignment = .top
After a couple of hours of confusion, here's how I got it to work under iOS 3.2. As dusker mentioned, using setBackgroundImage instead of setImage did the job for me.
CGRect myButtonFrame = CGRectMake(0, 0, 250, 250);
UIImage *myButtonImage = [UIImage imageNamed:#"buttonImage"];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myButton setBackgroundImage:myButtonImage forState:UIControlStateNormal];
[myButton setFrame: myButtonFrame];
[myButton setContentMode: UIViewContentModeScaleAspectFit];
The answer is to use a UIImageView with all the lovely Content Mode settings you want, and then layer a custom button on top of it. Dumb that you can't do that all in one shot, but it appears that you can't.
These two things (which are quite hard to find initially) will stretch your UIButton image to fit the button size:
one should always try to set such in the Storyboard rather than code.
Found a fix for this. Set the adjustsImageWhenHighlighted property of UIButton to NO.
UIButton *b = [[UIButton alloc] initWithFrame:rect];
[b setImage:image forState:UIControlStateNormal];
[b.imageView setContentMode:UIViewContentModeScaleAspectFill];
[b setAdjustsImageWhenHighlighted:NO];
Hope this helps. Feel free to comment below, I will follow up on any questions that you have.
My answer is similar to Kuba's. I needed my image to be programatically set.
UIImage *image = [[UIImage alloc] initWithContentsOfFile:...];
[button setBackgroundImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFill; //this is needed for some reason, won't work without it.
for(UIView *view in button.subviews) {
view.contentMode = UIViewContentModeScaleAspectFill;
}
Only solution which worked for me:
[button setImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
Swift 3
self.firstButton.imageView?.contentMode = .scaleAspectFill
For anyone experiencing this on iOS 15 and Xcode 13, see Matt's answer in this other question.
The behavior of Xcode changed and now defaults UIButtons from the library to the plain style, which prevents the child image from scaling as expected.
Instead of setImage try setBackgroundImage
I believe we have a simple interface builder issue here - apparently the IB ignores any content-mode changes AFTER you have set the image-property.
the solution is as simple: set the content mode, remove previously set image-names (make sure you remove it in all states, default, highlighted etc.), then re-enter the desired image-names in all desired states - et voilà.
I also advice to have a look at the adjustsImageWhenHighlighted UIButton property to avoid weird deformations of the image, when the button is pressed.
In trying to figure this out, my method got a bit hackier as time went on, and I wound up subclassing UIButton and overriding setHighlighted:
For me it works to just knock down the image alpha to .5, because they're on a black background.
However, it only works if I comment out [super setHighlighted:] (where it appears the image-stretchy code is going on), which just doesn't feel like the right way to solve this at all...everything seems to be working fine, though. We'll see how it holds up as I keep working on it.
- (void)setHighlighted:(BOOL)highlight {
if (highlight) {
[self.imageView setAlpha:.5];
} else {
[self.imageView setAlpha:1];
}
// [super setHighlighted:highlight];
}
If anyone looking for answer that work in iOS 6 and iOS 7 and storyboard:
You can set image in your storyboard:
And then:
for(UIView* testId in self.subviews) {
if([testId isKindOfClass:[UIImageView class]])
[testId setContentMode:UIViewContentModeScaleAspectFill];
}
If the UIButton does not seem to listen to the layout constraint settings, do check whether the images are larger than the button size. Always use the #2x and #3x images for retina resolutions.