Avoid code repetition when coding UIButtons in iOS - ios

I'm pretty new to iOS programming and Objective-C in general, so this question has probably been asked quiet a few times. Anyway:
In my iOS app, I have several UIButtons that I create the following way:
UIButton *webButton = [UIButton buttonWithType:UIButtonTypeCustom];
[webButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
webButton.frame = CGRectMake(10, 315, 300, 44);
[webButton setBackgroundImage:[UIImage imageNamed:#"WebButton.png"] forState:UIControlStateNormal];
[webButton setBackgroundImage:[UIImage imageNamed:#"WebButtonPressed.png"] forState:UIControlStateHighlighted];
Since I want the title of the button to be easily editable, I then add UILabels to the button instead of having them be part of the image used as the buttons background image.
UILabel *webLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 300, 15)];
webLabel.text = #"Some website";
webLabel.font = [UIFont boldSystemFontOfSize:16.0];
webLabel.textColor = [UIColor colorWithRed:62.0 / 255 green:135.0 / 255 blue:203.0 / 255 alpha:1];
webLabel.textAlignment = UITextAlignmentCenter;
webLabel.backgroundColor = [UIColor clearColor];
[webButton addSubview:webLabel];
[webLabel release];
This gets very tedious, when you have to go through this procedure every single time you want to create a new button. What is the best way to simplify this process, so I don't have to repeat myself over and over again when coding buttons?
Thanks.

I suspect want you want to do is to create a subclass of UIButton. That way you write your code once, but use it for any number of buttons. Something a bit like this:
// in your .h file
#import <UIKit/UIKit.h>
#interface WebButton : UIButton
+ (WebButton*) webButtonWithBackgroundImageNamed: (NSString*) imageName title: (NSString*) string andTarget: (id) target;
#end
// in your .m file
#import "WebButton.h"
#implementation WebButton
+ (WebButton*) webButtonWithBackgroundImageNamed: (NSString*) imageName title: (NSString*) string andTarget: (id) target;
{
WebButton *webButton = [WebButton buttonWithType:UIButtonTypeCustom];
[webButton addTarget:target action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
webButton.frame = CGRectMake(0, 0, 300, 44);
[webButton setBackgroundImage:[UIImage imageNamed: imageName] forState:UIControlStateNormal];
[webButton setBackgroundImage:[UIImage imageNamed: [NSString stringWithFormat:#"%#pressed", imageName]] forState:UIControlStateHighlighted];
UILabel *webLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 300, 15)];
webLabel.text = string;
webLabel.font = [UIFont boldSystemFontOfSize:16.0];
webLabel.textColor = [UIColor colorWithRed:62.0 / 255 green:135.0 / 255 blue:203.0 / 255 alpha:1];
webLabel.textAlignment = UITextAlignmentCenter;
webLabel.backgroundColor = [UIColor clearColor];
[webButton addSubview:webLabel];
[webLabel release];
return webButton;
}
And then to create and add the button to a view something a bit like this:
WebButton* webButton = [WebButton webButtonWithBackgroundImageNamed:#"WebButton" title:#"testing" andTarget:self];
CGRect webButtonFrame = [webButton frame];
webButtonFrame.origin.x = 10;
webButtonFrame.origin.y = 30;
[webButton setFrame:webButtonFrame];
[[self window] addSubview:webButton];

Related

Cannot get UIButton to programmatically call action in iOS

I cannot get my button to fire the associated method. I am not using IB or anything like that (all programmatic). The _mainViewController is passed in during custom init, just to clarify (although this should have nothing to do with the button). Please see my code snips:
viewcontroller.h
#import <UIKit/UIKit.h>
#interface CSNWZSSViewController : UIViewController
- (void)doneButtonPressed;
#property UIViewController *mainViewController;
#property UIButton *doneButton;
#end
viewcontroller.m
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _mainViewController.view.frame.size.width, 45)];
headerView.backgroundColor = [UIColor darkGrayColor];
_doneButton = [[UIButton alloc] initWithFrame:CGRectMake(_mainViewController.view.frame.size.width - 100, 0, 100, headerView.frame.size.height)];
[_doneButton addTarget:self
action:#selector(doneButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
[_doneButton setTitle:#"Done" forState:UIControlStateNormal];
_doneButton.tintColor = [UIColor whiteColor];
_doneButton.backgroundColor = [UIColor colorWithRed:0 green:.77 blue:0 alpha:1];
[headerView addSubview:_doneButton];
CGRect headerLabelFrame = CGRectMake(5, 5, headerView.frame.size.width - 105, headerView.frame.size.height - 5);
UILabel *headerLabel = [[UILabel alloc] initWithFrame:headerLabelFrame];
headerLabel.text = #"test header";
headerLabel.textColor = [UIColor whiteColor];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.font = [UIFont systemFontOfSize:20.0f];
headerLabel.lineBreakMode = NSLineBreakByTruncatingTail;
[headerView addSubview:headerLabel];
[self.view addSubview:headerView];
}
- (void)doneButtonPressed
{
NSLog(#"button pressed");
}
Update 10/9/16 using buttonWithType init and explicit userInteractionEnabled
_doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_doneButton addTarget:self
action:#selector(doneButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
[_doneButton setTitle:#"Done" forState:UIControlStateNormal];
_doneButton.tintColor = [UIColor whiteColor];
_doneButton.backgroundColor = [UIColor blackColor]; //[UIColor colorWithRed:0 green:.77 blue:0 alpha:1];
_doneButton.frame = CGRectMake(_mainViewController.view.frame.size.width - 100, 0, 100, headerView.frame.size.height);
_doneButton.userInteractionEnabled = YES;
[headerView addSubview:_doneButton];
Note 12/9/16 the _mainViewController object is passed in here:
CSNWZSSViewController *CSNWZSSVC = [[CSNWZSSViewController alloc] initWithRichTextString:source withTitleString:title forViewController:self.viewController];
[self.viewController.view addSubview:CSNWZSSVC.view];
Solution with matt's help (see below) The context was getting messed up due to the lack of adding the new view controller.
CSNWZSSViewController *CSNWZSSVC = [[CSNWZSSViewController alloc] initWithRichTextString:source withTitleString:title forViewController:self.viewController];
[self.viewController addChildViewController:CSNWZSSVC];
[self.viewController.view addSubview:CSNWZSSVC.view];
The _mainViewController is passed in during custom init
I'm going to guess that this is the problem — that you are mismanaging this view controller and that it is not being correctly made part of the view controller hierarchy, and in fact may even be going out of existence so that there is no one to send the button action message to.
edit Yes, now that you've posted more code, I'm clearly right:
CSNWZSSViewController *CSNWZSSVC = [[CSNWZSSViewController alloc] initWithRichTextString:source withTitleString:title forViewController:self.viewController];
[self.viewController.view addSubview:CSNWZSSVC.view];
That is totally wrong behavior. You cannot arbitrarily add another view controller's view to yours. There is a strict dance for managing a child view controller, and you are not doing the dance.
Try:
UIButton *theButton = [UIButton buttonWithType:UIButtonTypeCustom];
And then set your frame.

Button Text not showing

When I try to post the following code, my app just shows an empty rectangle where the button's text should be. I am a beginner at xcode and I have determined this code from other tutorials.
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *player1 = [[UILabel alloc]initWithFrame:CGRectMake(35, 120,130, 30)];
[player1 setText:#"Player"];
player1.layer.borderWidth = 1.0;
player1.layer.borderColor = [UIColor blackColor].CGColor;
player1.textAlignment = UITextAlignmentCenter;
[self.view addSubview: player1];
UIButton *score1 = [[UIButton alloc]initWithFrame:CGRectMake(165, 120, 60, 30)];
[score1 setTitle:#"0" forState:UIControlStateNormal];
score1.layer.borderWidth = 1.0;
score1.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview: score1];
UILabel *player2 = [[UILabel alloc]initWithFrame:CGRectMake(35, 150, 130, 30)];
[player2 setText:#"Opponent"];
player2.layer.borderWidth = 1.0;
player2.layer.borderColor = [UIColor blackColor].CGColor;
player2.textAlignment = UITextAlignmentCenter;
[self.view addSubview: player2];
}
Like I said, everything but the text in the button is showing up.
The reason why the button looks blank is because its text color is actually white. Just give it a different color and 0 will now show:
score1.layer.backgroundColor = [UIColor blackColor].CGColor;
If you don't want to change the button background color, you may want to set the text color:
[score1 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
Read Question: [initWithFrame:frame] vs. [UIButton buttonWithType], for more about creating a UIButton with these different methods.
The problem is the way you're creating the button:
UIButton *score1 = [[UIButton alloc]initWithFrame:CGRectMake(165, 120, 60, 30)];
That's not how you do it. Do it like this:
UIButton *score1 = [UIButton buttonWithType:UIButtonTypeSystem];
score1.frame = CGRectMake(165, 120, 60, 30);
All will be well after that!

UIButton text of label not visible

Problem: If the user goes on the iPhone/iPad to "Settings - General - Accessibility - Increase Contrast" and switches on "Darken Colors" the text from my buttons disappears.
Here is my code for creating the buttons:
buttonCurrent = [UIButton buttonWithType:UIButtonTypeSystem];
buttonCurrent.translatesAutoresizingMaskIntoConstraints = NO;
buttonCurrent.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
buttonCurrent.titleLabel.textAlignment = NSTextAlignmentCenter;
buttonCurrent.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
buttonCurrent.titleLabel.numberOfLines = 2;
buttonCurrent.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
buttonCurrent.backgroundColor = [UIColor whiteColor];
[buttonCurrent setTitle:NSLocalizedString(#"Add the reading with the current date", nil) forState:UIControlStateNormal];
[buttonCurrent addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
Thanks for the help.
I changed the code to:
buttonCurrent = [UIButton buttonWithType:UIButtonTypeCustom];
buttonCurrent.translatesAutoresizingMaskIntoConstraints = NO;
buttonCurrent.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
[buttonCurrent setTitleColor:self.view.tintColor forState:UIControlStateNormal];
[buttonCurrent setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[buttonCurrent setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
buttonCurrent.titleLabel.textAlignment = NSTextAlignmentCenter;
buttonCurrent.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
buttonCurrent.titleLabel.numberOfLines = 2;
buttonCurrent.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
buttonCurrent.backgroundColor = [UIColor grayColor];
[buttonCurrent setTitle:NSLocalizedString(#"Add the reading with the current date", nil) forState:UIControlStateNormal];
It looks now like the UIButtonTypeSystem and it works also with system setting "Darken Colors".
all code is fine except first line.
buttonCurrent = [UIButton buttonWithType:UIButtonTypeCustom];
UIButtonTypeSystem have default blue color as a back ground in greater than iOS7. You should always use UIButtonTypeCustom, so that it does not shows the effect as you are experience.
And also please give frame. I checked your code and you have not given frame for button. Please do that first.
UIButton *buttonCurrent = [UIButton buttonWithType:UIButtonTypeCustom];
buttonCurrent.translatesAutoresizingMaskIntoConstraints = NO;
buttonCurrent.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
buttonCurrent.titleLabel.textAlignment = NSTextAlignmentCenter;
buttonCurrent.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
buttonCurrent.titleLabel.numberOfLines = 2;
buttonCurrent.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
buttonCurrent.backgroundColor = [UIColor whiteColor];
buttonCurrent.frame = CGRectMake(0, 50, 320, 80);
[buttonCurrent setTitleColor:[UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0] forState:UIControlStateNormal];
[buttonCurrent setTitle:#"Add the reading with the current date" forState:UIControlStateNormal];
[buttonCurrent addTarget:self action:#selector(back:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonCurrent];
All code is fine except first line
buttonCurrent = [UIButton buttonWithType:UIButtonTypeCustom];
UIButtonTypeSystem have default blue color as a back ground in greater than iOS7. You should always use UIButtonTypeCustom, so that it does not shows the effect as you are experience.

Title of a Custom UIBarButtonItem from a UIButton not showing

I made a custom UIBarButtonItem from a UIButton. The custom bar button is visible, the action works, the size is correct, and the background color can be seen; however the manually set title cannot be seen. maybe background is laid over the text? I'm not sure, help?
In viewDidLoad:
UIButton *resetButton = [UIButton buttonWithType:UIButtonTypeCustom];
resetButton.frame = CGRectMake(0, 0, 65, 30);
[resetButton addTarget:self action:#selector(speakPhrase:) forControlEvents:UIControlEventTouchUpInside];
resetButton.titleLabel.font = [UIFont fontWithName:#"ProximaNova-Bold" size:19];
resetButton.titleLabel.text = #"RESET";
resetButton.titleLabel.textColor = [UIColor whiteColor];
resetButton.backgroundColor = [UIColor redColor];
resetButton.showsTouchWhenHighlighted = YES;
UIBarButtonItem *resetBarBTN = [[UIBarButtonItem alloc] initWithCustomView:resetButton];
self.navigationItem.rightBarButtonItem = resetBarBTN;
You should set the title for button of using setTitle:forState: for particular control states, replace your code with below
UIButton *resetButton = [UIButton buttonWithType:UIButtonTypeCustom];
resetButton.frame = CGRectMake(0, 0, 65, 30);
[resetButton addTarget:self action:#selector(speakPhrase:) forControlEvents:UIControlEventTouchUpInside];
resetButton.titleLabel.font = [UIFont fontWithName:#"ProximaNova-Bold" size:19];
[resetButton setTitle:#"RESET" forState:UIControlStateNormal]; //change this line in your code
resetButton.titleLabel.textColor = [UIColor whiteColor];
resetButton.backgroundColor = [UIColor redColor];
resetButton.showsTouchWhenHighlighted = YES;
UIBarButtonItem *resetBarBTN = [[UIBarButtonItem alloc] initWithCustomView:resetButton];
self.navigationItem.rightBarButtonItem = resetBarBTN;
Use setTitle:forState to set button title. For example
[resetButton setTitle:#"text" forState:UIControlStateNormal]

Set custom titleLabel properties for multiple UIButtons

I've got a custom button like:
UIButton *catBtn1 = [UIButton buttonWithType:UIButtonTypeCustom];
catBtn1.frame = CGRectMake(0, 344, 427, 67);
catBtn1.titleLabel.font = categoryFont;
catBtn1.titleLabel.textColor = [UIColor whiteColor];
catBtn1.titleLabel.frame = CGRectMake(52, 21, 150, 15);
catBtn1.titleLabel.textAlignment = UITextAlignmentLeft;
Is there a quick way to set all these titleLabel properties for all my buttons without doing this for each button? I tried assigning an instance of UILabel to catBtn1.titleLabel but that didn't work...
You can create method for button like this...
-(UIButton *) customBtn:(NSString *)btntxt:(CGFloat)btnx:(CGFloat)btny:(CGFloat)btnwidth
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
//[btn setTitle:btntxt forState:UIControlStateNormal];
btn.titleLabel.text = btntxt;
btn.titleLabel.font = categoryFont;
btn.titleLabel.textColor = [UIColor whiteColor];
btn.titleLabel.frame = CGRectMake(52, 21, 150, 15);
btn.titleLabel.textAlignment = UITextAlignmentLeft;
[btn setFrame:CGRectMake(btnx, btny, btnwidth, 40)];
return btn;
}
and you can call it like this any number of time when you need it
[YOURVIEW_OBJECT addSubview:[self customBtn:#"Samanmalliset" : 165:20 :115]];
You can create method that sets these properties and call it for each of your buttons.

Resources