I'm making an app where I've got three buttons on the screen. One of the buttons must always be selected. When the app loads the first button is set to selected, and preforms its action. When the user presses another button, the current button is deselected and the new one is selected.
I'm a little new to Objective-C. This is what I came up with, but none of what I was expecting works.
I've setup the buttons outlets in the header.
- (IBAction)buttonSelector:(id)sender
{
firstButton.selected = YES;
secondButton.selected = NO;
thirdButton.selected = NO;
if (firstButton.selected = YES)
{
[firstbutton setBackgroundImage:[UIImage imageNamed:"selected.png"]];
secondButton.selected = NO;
[secondButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
thirdButton.selected = YES;
[thirdButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
} else if (secondButton.selected = YES)
{
[secondButton setBackgroundImage:[UIImage imageNamed:"selected.png"]];
firstButton.selected = NO;
[firstButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
thirdButton.selected = NO;
[firstButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
} else if (thirdButton.selected = YES)
{
[thirdButton setBackgroundImage:[UIImage imageNamed:"selected.png"]];
firstButton.selected = NO;
[firstButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
secondButton.selected = NO;
[secondButton setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
} else {
[sender setBackgroundImage:[UIImage imageNamed:"un_selected.png"]];
}
}
Edit 1:
I tried the UISegmentedControl, but it doesn't appear to be able to be customized enough for what I'm looking for. Ideally the buttons will be more along these lines:
http://i.stack.imgur.com/LPwoR.jpg
The buttons are going to have a background image that will change
You should use UISegmentControl for this. That is the exact feature you are looking for. Here is the apple documentation on this
Here is a tutorial from Ray wenderlich on how to customize UI elements which includes a UISegmentControl.
For eg:-
NSArray *itemArray = [NSArray arrayWithObjects: #"One", #"Two", #"Three", nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:itemArray];
segmentedControl.frame = CGRectMake(35, 200, 250, 50);
segmentedControl.segmentedControlStyle = UISegmentedControlStylePlain;
Just do this task with for loop, firstly just set image to all of your button then change image of selected image.
Related
I have the following code that changes the background of the Cancel button in the UISearchBar.
for( UIView *subview in self.searchBar.subviews ){
if ([subview isKindOfClass:[UIButton class]]) {
[(UIButton *)subview setEnabled:YES];
[(UIButton *)subview setTitle:#"New Button Text" forState:UIControlStateNormal];
((UIButton *)subview).tintColor = [UIColor colorWithRed:4/255.0 green:119/255.0 blue:152/255.0 alpha:1.0];
}
}
The problem is that this code does not work in iOS7! What changed in the structure of the views in the UISearchBar?
Edit: Tested here and this is the new Hierarchy of the UISearchBar:
UISearchBar:
---UIView:
------UISearchBarBackground
------UISearchBarTextField
------UINavigationButton
The problem is that i cannot test if ([sub isKindOfClass:[UINavigationButton class]]). This line throws a compile error: Use of undeclared identifier: UINavigationButton
[Edited]
Try this codes.
Add in AppDelegate if you want to change all cancel button.
[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor redColor],
UITextAttributeTextColor,
[UIColor whiteColor],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, 0)],
UITextAttributeTextShadowOffset,
nil]
forState:UIControlStateNormal];
In iOS7 , we need to add objectAtIndex:0 and subviews.
The searchBar sub views hierarchy has been changed in iOS7, try the below:
in iOS7:
NSArray *searchBarSubViews = [[self.searchBar.subviews objectAtIndex:0] subviews];
iOS6 and before:
NSArray *searchBarSubViews = self.searchBar.subviews;
Solution: I created my own button. This way I can manage all the properties without having to discover what Apple did with the elements
I only have to create a UIView aux to contain the searchBar and the new Button.
self.searchBar.showsCancelButton = NO; //don`t show the original cancelButton
self.cancelSearchButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.cancelSearchButton.frame = CGRectMake(250, 6, 60, 31);
[self.cancelSearchButton setTitle:#"Cancelar" forState:UIControlStateNormal];
[self.cancelSearchButton addTarget:self action:#selector(searchBarCancelButtonClicked) forControlEvents:UIControlEventTouchUpInside];
NSString *fontName = [[self.cancelSearchButton titleLabel] font].fontName;
[[self.cancelSearchButton titleLabel] setFont:[UIFont fontWithName:fontName size:11.0]];
UIView *aux = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
aux.backgroundColor = [UIColor colorWithRed:230/255.0 green:230/255.0 blue:230/255.0 alpha:1.0];
aux.layer.borderWidth = 1.0f;
aux.layer.borderColor = [UIColor lightGrayColor].CGColor;
aux.layer.cornerRadius = 0.0f;
[aux addSubview:self.searchBar];
[aux addSubview:self.cancelSearchButton];
- (void)searchBarCancelButtonClicked{
//do whatever I want to do here
}
You can take advantage of the iOS Runtime Property _cancelButton to achieve this.
UIButton *cancelButton = [self.searchBar valueForKey:#"_cancelButton"];
[cancelButton setTitleColor:[UIColor yourColor] forState:UIControlStateNormal];
For changing text
[self.searchBar setValue:#"customString" forKey:#"_cancelButtonText"];
I Follow the comment and try to fix my problem,but still not working.
when i run the test demo on the simulator,i get this:
run the demo project view
and i click the test2, i want to change button title before clear the button title, but i
get this :
after i click test2 button
i can not clear the button title when click another button.
anyone can help ??
Here is my code
-(void)addbutton
{
for (int i=0; i<3; i++)
{
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake((i*100), 0, 100, 100)];
button.titleLabel.text = #"";
[button setTag:i];
[button setTitle:[self.demoDataArray objectAtIndex:i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.backgroundColor = [UIColor clearColor];
[button addTarget:self action:#selector(setButtonTitle:) forControlEvents:UIControlEventTouchUpInside];
[self.demoView addSubview:button];
}
}
-(IBAction)setButtonTitle:(id)sender
{
if ([sender tag] == 0)
{
self.demoDataArray = [[NSArray alloc] initWithObjects:#"test5", #"test6", #"test7", #"test8", nil];
[self addbutton];
}
else if([sender tag] == 1)
{
self.demoDataArray = [[NSArray alloc] initWithObjects:#"test9", #"test10", #"test11", #"test12", nil];
[self addbutton];
}
else if([sender tag] == 3)
{
self.demoDataArray = [[NSArray alloc]initWithObjects:#"test13", #"test14", #"test15", #"test16", nil];
[self addbutton];
}
}
Every time any button is pressed, you instantiate new buttons and add them on top of the other ones. You probably want to just update the existing buttons. Try this for your -addButton method instead:
-(void)addbutton
{
for (int i=0;i<3;i++)
{
NSInteger tag = i+1;
UIButton *button = (UIButton *)[self.view viewWithTag:tag];
if (!button)
{
button = [[UIButton alloc] initWithFrame:CGRectMake((i*100), 0, 100, 100)];
[button addTarget:self action:#selector(setButtonTitle:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:tag];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.backgroundColor = [UIColor clearColor];
[self.demoView addSubview:button];
}
button.titleLabel.text = #""; // Not actually sure you need this...
NSString *titleText = nil;
if (i < self.demoDataArray.count)
titleText = [self.demoDataArray objectAtIndex:i];
[button setTitle:titleText forState:UIControlStateNormal];
}
}
Now the button is instantiated, given a target and action, tagged, and added into the button hierarchy only when it doesn't already exist. Every time a button is tapped after that, only the titles will be updated.
Also, very important:: in order for -viewWithTag: to work, you have to use a tag for your buttons that is not equal to 0, the default tag - otherwise the button's superview will be returned. This means you'll need to make the following changes in your button handler, which already had a bug with checking the tags (checking against 3 rather than 2). Increment the tags to start at 1 and end with 3 like so:
-(IBAction)setButtonTitle:(id)sender
{
if ([sender tag] == 1)
{
self.demoDataArray = [[NSArray alloc] initWithObjects:#"test5",#"test6",#"test7",#"test8", nil];
[self addbutton];
}
else if([sender tag] == 2)
{
self.demoDataArray = [[NSArray alloc] initWithObjects:#"test9",#"test10",#"test11",#"test12", nil];
[self addbutton];
}
else if([sender tag] == 3)
{
self.demoDataArray = [[NSArray alloc]initWithObjects:#"test13",#"test14",#"test15",#"test16", nil];
[self addbutton];
}
}
That method could use some cleanup as well to eliminate duplicated code and it's probably more appropriate to use a switch statement here anyways. But that's neither here nor there.
OK, this should probably get you up and running. I didn't test or compile this so if you do have some problem with the compiler that you're not able to work through on your own please let me know and I'll see if I can spot the issue.
try this
- (IBAction)firstbtn:(UIButton *)sender {
[secondbtn setTitle:#"" forState:UIControlStateNormal];
}
I was wondering which method is the easiest or "smartest" way of making a pause menu for games?
I don´t have that much experience with creating game pause menus so I´ve tried 2 methods that I came up with by my own. Both or in code beneath this text.
The first method I tried was to put a black almost transparent filter on top of the game, that I paused. I was successful with pausing everything except the touches made underneath the filter on my uiimages. I thought that putting a new uiimage on top of the current one would disable the touches made on the uiimages underneath it. I tried as well with touchenabled = NO but still nothing.
-(IBAction)pause{
NSLog(#"pause");
[countdowntimer invalidate];
[self.rubin1 stopAnimating];
[self.rubin2 stopAnimating];
[self.rubin3 stopAnimating];
Pause.enabled = NO;
music1.enabled = NO;
music2.enabled = NO;
sfx1.enabled = NO;
sfx2.enabled = NO;
//PauseMenu background
UIImage *image1 = [UIImage imageNamed: #"filter2.png"];
pausefilter = [[[UIImageView alloc] initWithImage:image1] autorelease];
CGRect newFrame1 = pausefilter.frame;
newFrame1 = CGRectMake(0,0, image1.size.width, image1.size.height);
pausefilter.frame = newFrame1;
[self.view addSubview:pausefilter];
[image1 release];
//Resume to Game
button1 = [UIButton buttonWithType:UIButtonTypeCustom];
button1.frame = CGRectMake(90, 146, 80, 18);
[button1 setImage:[UIImage imageNamed:#"RESUME.png"] forState:UIControlStateNormal];
[button1 addTarget:self action:#selector(resume) forControlEvents:UIControlEventTouchUpInside];
[ self.view addSubview: button1 ];
//End Game
button2 = [UIButton buttonWithType:UIButtonTypeCustom];
button2.frame = CGRectMake(260, 140, 180, 30);
[button2 setImage:[UIImage imageNamed:#"EndGame.png"] forState:UIControlStateNormal];
[button2 addTarget:self action:#selector(end) forControlEvents:UIControlEventTouchUpInside];
[ self.view addSubview: button2 ];
[sharedSoundManager pausePlayingMusic];
}
The second method I tried was to go back (switch view) to the options on the main menu to use the settings from there instead but I wasn´t able to resume back to where I paused the game. Instead the game restarted from the beginning.
-(IBAction)pause{
NSLog(#"pause");
[countdowntimer invalidate];
[self.rubin1 stopAnimating];
[self.rubin2 stopAnimating];
[self.rubin3 stopAnimating];
Pause.enabled = NO;
music1.enabled = NO;
music2.enabled = NO;
sfx1.enabled = NO;
sfx2.enabled = NO;
menureturn = [[MainMenu alloc] initWithNibName:#"MainMenu" bundle: nil];
menureturn.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:menureturn animated: YES];
self.menureturn.Start.hidden = YES;
self.menureturn.option.hidden = YES;
self.menureturn.OptionsHeadtitle.hidden = NO;
self.menureturn.HowToPlayHeadtitle.hidden = YES;
self.menureturn.howtoplay.hidden = YES;
self.menureturn.filter.hidden = NO;
self.menureturn.music1.hidden = NO;
self.menureturn.music2.hidden = YES;
self.menureturn.SFXimage.hidden = NO;
self.menureturn.Musicimage.hidden = NO;
self.menureturn.sfx1.hidden = NO;
self.menureturn.sfx2.hidden = YES;
self.menureturn.credits.hidden = YES;
self.menureturn.back.hidden = YES;
self.menureturn.creditsinfo.hidden = YES;
self.menureturn.resume.hidden = NO;
self.menureturn.endgame.hidden = NO;
[sharedSoundManager pausePlayingMusic];
}
Is there a third option of how to make a god pause menu or just redo one of the two I already tried?
You can have a BOOL variable like
BOOL isGamePaused
Now when you are playing game i.e running not paused assign
isGamePaused = NO;
While you pause
isGamePaused = YES;
Now while playing animation or something like that you can use condition like
if(!isGamePaused) { ProceedAnimation;}
Hope this helps
The best thing to disable any event is to create a new element in your pause menu which will be the first responder and catches all events. So nothing can arrive to your game's interface ;)
I am using a UISegmentedControl with some custom images:
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:nil];
[segmentedControl insertSegmentWithImage:[UIImage imageNamed:#"0.png"] atIndex:0 animated:NO];
[segmentedControl insertSegmentWithImage:[UIImage imageNamed:#"1.png"] atIndex:1 animated:NO];
[segmentedControl insertSegmentWithImage:[UIImage imageNamed:#"2.png"] atIndex:2 animated:NO];
segmentedControl.frame = CGRectMake(0, 0, 90, 30);
[self.view addSubview:segmentedControl];
[segmentedControl release];
This part works fine. But, it still uses Apple's styling for the control and just adds my images over it. Is there a way that I don't have to use Apple's styles, and customize the conrol with my own images with no background? I would also like to have my own "selected" state images.
Possible?
Nic,
After playing with this for a while, I decided to simply "roll my own" in a way.
I made some button images in photoshop and got everything looking like a segmented control. Then, I set a different image for the "selected" states of all the buttons. When one button was pressed, I called setSelected:NO to the others. Then, I handled whatever I needed to do.
I'd love to hear other solutions.
In addition to DexterW's answer. I had came to same decision - to mimic UISegmentedControl using UIButtons only.
However its not a simple task to mimic UISegmentControl. I tried to use Selected state of a UIButton but UIButton wont work as expected if set same settings (bg image, font color) for Hightlighted and Selected states. In such case when segment looks selected its still "pressable" visually. So, to avoid it and make buttons set acting more like UISegmentedControl I didn't use a selected state at all. Instead Id decided to change appearance of selected button in code so that normal and highlighted states are the same visually for selected button and different for unselected one.
Assume I have 3 buttons segmentedControl (LeftSgm | MiddleSgm | RightSgm) and for normal state Im using bg picture named "segment_default" and font color white and for selected state its bg picture named "segment_active" and black font. So in onTouchDown:
-(IBAction)onTopMenuTap:(id)sender
{
int newSelectedSegmentIndex;
if (sender == btnLeftSgm)
newSelectedSegmentIndex=0;
else if (sender == btnMiddleSgm)
newSelectedSegmentIndex=1;
else if (sender == btnRightSgm)
newSelectedSegmentIndex=2;
else
return;
NSLog(#"Tapped segment index %d while old one is %d",newSelectedSegmentIndex,selectedSegmentIndex);
if (newSelectedSegmentIndex==selectedSegmentIndex)
return;
[self handleSegmentAppearenace:newSelectedSegmentIndex];
//do whatever its need to be done
...
}
and the called method is
-(void)handleSegmentAppearenace:(int)newSelectedSegmentIndex
{
if (selectedSegmentIndex==0){
[btnLeftSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_default_left"] forState:UIControlStateNormal];
[btnLeftSgm setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
btnLeftSgm.highlighted = NO;
}
else if (selectedSegmentIndex==1){
[btnMiddleSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_default_center"] forState:UIControlStateNormal];
[btnMiddleSgm setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
btnMiddleSgm.highlighted = NO;
}
else if (selectedSegmentIndex==2){
[btnRightSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_default_right"] forState:UIControlStateNormal];
[btnRightSgm setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
btnRightSgm.highlighted = NO;
}
if (newSelectedSegmentIndex==0){
[btnLeftSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_active_left"] forState:UIControlStateNormal];
[btnLeftSgm setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnLeftSgm.highlighted = YES;
}
else if (newSelectedSegmentIndex==1){
[btnMiddleSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_active_center"] forState:UIControlStateNormal];
[btnMiddleSgm setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnMiddleSgm.highlighted = YES;
}
else if (newSelectedSegmentIndex==2){
[btnRightSgm setBackgroundImage:[UIImage imageNamed:#"segmented_control_active_right"] forState:UIControlStateNormal];
[btnRightSgm setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnRightSgm.highlighted = YES;
}
}
All three buttons are bound in IB to corresponding properties (btnRightSgm etc). Also for "touch up event" onTopMenuTap is bound.
Cant say its a best idea but it works perfectly for me.
I've created a UIButton on a view and on action of the UIButton[UIButton* button1_obj] one more button[UIButton* button2_obj] is created on same view.
i'm facing these 2 issues...please guide me how to proceed.
button1_obj is appearing when i run my project, but its not being clicked or highlighted, nor any exception is thrown.
On action of button1_obj , button2-obj has to appear on the same view, how to clear the view before placing button2_obj on it.
Code for question (1):
-(void)start
{
NSLog(#"--------------------------------------------------------------------");
NSLog(#"Entered CView start");
//define size and position of view
subMainView_G_obj = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 480, 320)]; //initilize the view
//subMainView_G_obj.autoresizesSubviews = YES; //allow it to tweak size of elements in view
UIButton_G_obj = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
UIButton_G_obj.frame = CGRectMake(100,70, 150, 50);
UIButton_G_obj.backgroundColor = [UIColor clearColor];
//UIButton_G_obj.adjustsImageWhenHighlighted = YES;
[UIButton_G_obj setTitle:#"UI" forState:UIControlStateNormal];
[UIButton_G_obj addTarget:self action:#selector(action:) forControlEvents:UIControlEventTouchUpInside];
[subMainView_G_obj addSubview:UIButton_G_obj];
UIButton_G_obj = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
UIButton_G_obj.frame = CGRectMake(100,150, 150, 50);
UIButton_G_obj.backgroundColor = [UIColor clearColor];
UIButton_G_obj.adjustsImageWhenHighlighted = YES;
[UIButton_G_obj setTitle:#"Configuration" forState:UIControlStateNormal];
[UIButton_G_obj addTarget:self action:#selector(action:) forControlEvents:UIControlEventTouchUpInside];
[subMainView_G_obj addSubview:UIButton_G_obj];
NSLog(#"Leaving CView start");
NSLog(#"--------------------------------------------------------------------");
}
- (void)action:(id) sender
{
NSLog(#"Inside action method.. On click of First View");
buttonUIObj = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
buttonUIObj.frame = CGRectMake(100,160,100,50);
[buttonUIObj setTitle:#"Next View" forState:UIControlStateNormal];
buttonUIObj.backgroundColor = [UIColor clearColor];
[subMainView_G_obj addSubview:buttonUIObj];
}
i've declare UIButton_G_obj,buttonUIObj,subMainView_G_obj GLOBALLY.
Hard to know what the problem with button1_obj is, without seeing code. However, for (2), you will probably want to remove button1_obj by calling [button1_obj removeFromSuperview].
About problem 1:
First of all both your buttons are named the same. Therefore you have a memory leak because your are allocating space for your button twice. Use different names for your buttons.
About problem 2:
You could hide button 2 until button 1 is pressed: In -(void)start
UIButton_G_obj_1.tag = 1;
...
UIButton_G_obj_2.hidden = YES;
UIButton_G_obj_2.tag = 2;
And in the action method you can unhide the button:
if (sender.tag == 1) {
UIButton_G_obj_2.hidden = NO;
}