how to change uibutton title at runtime in objective c? - iphone

I know this question is asked many a times,and i am also implementing the same funda for chanding the title of the uibutton i guess.
Let me clarify my problem first. I have one uibutton named btnType, on clicking of what one picker pops up and after selecting one value,i am hitting done button to hide the picker and at the same time i am changing the the title of the uibutton with code
[btnType setTitle:btnTitle forState:UIControlEventTouchUpInside];
[btnType setTitleColor:[UIColor redColor] forState:UIControlEventAllEvents];
But with my surpriaze,it is not changed and application crashes with signal EXC_BAD_ACCESS. I am not getting where i am making mistake.I have allocated memory to the btnType at viewdidLoad. Also I am using
-(IBAction)pressAddType
{
toolBar.hidden = FALSE;
dateTypePicker.hidden = FALSE;
}
event on pressing the button to open the picker. Also i would like to mention that i have made connection with IB with event TouchUpInside for pressAddType.
Any guesses? I will be grateful if you could help me.
Thanks.
UPDATE:
#interface AddSettingPage : UIViewController<UITextFieldDelegate>
{
IBOutlet UIButton *btnType;
NSString *btnTitle;
}
#property (nonatomic, retain) IBOutlet UIButton *btnType;
-(IBAction)pressAddType;//:(id)sender;
Also
#synthesize btnType,btnTitle;

try
[yourButton setTitle:#"your title" forState:UIControlStateNormal];
[yourButton setTitle:#"your title" forState:UIControlStateSelected];
[yourButton setTitle:#"your title" forState:UIControlStateHighlighted];
when the picker is dismissed, the button (which was the control that hold focus) will be in the selected state (or the highlighted .. check it out).
and stop using UIControlEventTouchUpInside in the forState: parameter. it is not a state, it is an event. you are passing an event identifier instead of a state identifier

The state you pass in setTitle should be something like UIControlStateNormal:
[b setTitle:#"" forState:UIControlStateNormal];

Instead of
- (IBAction) pressAddType;
declare
- (IBAction) pressAddType:(id)sender; //or (UIButton *)sender
and define it like:
-(IBAction)pressAddType:(id)sender
{
toolBar.hidden = FALSE;
dateTypePicker.hidden = FALSE;
[(UIButton *)sender setTitle:btnTitle forState:UIControlEventTouchUpInside];
[(UIButton *)sender setTitleColor:[UIColor redColor] forState:UIControlEventAllEvents];
}
As you can see, you don't need to have your button as an ivar because it is passed as a parameter of the method when pressed.

This answer why not button title change only,EXC_BAD_ACCESS error only you getting when an object you trying to access those object is not in memory of stack or that object has null value. So my advice is please check your object (btnTitle) is in memory or not?

Related

toggle UIButton text programmatically with a conditional statement

Here's my code (it's wrapped in an IBAction that is called when the button is pressed):
if (myButton.currentTitle == #"test") {
[myButton setTitle:#"test2" forState:UIControlStateNormal];
}
if (myButton.currentTitle == #"test2") {
[myButton setTitle:#"test" forState:UIControlStateNormal];
}
I want the UIButton text to toggle when pressed (if text = "test" then change to "test2" and when pressed if text = "test2" change to "test").
I do have an IBOutlet connected for myButton and the the IBAction connected to myButton--so I am pretty sure it isn't a problem with my connections.
For some reason this isn't working, I'm sure I am missing something very simple.
use isEqualToString: instead of ==
This is because you lack a control statement that skips the second if when the first one succeeds. When you come into the block with "test", you switch it to "test2", and then the second condition succeeds immediately, and you turn "test2" back into "#test".
You can an an else to fix this, but you can skip the if altogether by using an NSArray that maps the current state to the new state.
// This should be made static, and initialized only once
NSDictionary *nextTitle = [NSDictionary dictionaryWithObjectsAndKeys:
#"test", #"test2", #"test2", #"test", nil];
// This line does the toggling
[myButton setTitle:[nextTitle valueForKey:myButton.currentTitle] forState:UIControlStateNormal];
if ([myButton.currentTitle isEqualToString:#"test"]) {
[myButton setTitle:#"test2" forState:UIControlStateNormal];
}
if ([myButton.currentTitle isEqualToString:#"test2"]) {
[myButton setTitle:#"test" forState:UIControlStateNormal];
}
Hope, this will help you...
Comparing user-visible strings is generally considered bad practice (and becomes tedious when you need to do i18n), especially with string literals since it's vulnerable to typos.
If you're just going to toggle between two states, the easiest thing to do is to use the UIControl.selected property (corresponding to UIControlStateSelected):
// In init
[myButton setTitle:#"test" forState:UIControlStateNormal];
[myButton setTitle:#"test2" forState:UIControlStateSelected];
[myButton setTitle:#"test2" forState:UIControlStateSelected|UIControlStateHighlighted];
// Toggle
myButton.selected = !myButton.selected;
It also makes the code a lot cleaner when you when you decide to toggle the button image/background/text colours too.
Note the slight gotcha: If you don't set the title for UIControlStateSelected|UIControlStateHighlighted it will use the title for UIControlStateNormal when the button is both selected and highlighted (touched).
When comparing strings to each other try using if([str1 compare:str2] == NSOrderedSame)

IOS 5 block unrecognized selector

I am trying to assign a block to a button object so that each time a button is pressed the block will execute. I have the following defined button subclass that holds the block for each unique button I create.
typedef void (^ButtonPressBlock)();
#interface PhotoButton : UIButton
{
ButtonPressBlock photoButtonPressed;
}
#property (copy) ButtonPressBlock photoButtonPressed;
#end
There is a #synthesize photoButtonPressed in the .m
In a separate UIViewController I #import "PhotoButton.h" and then in that view controller I have a method that creates the buttons. The code looks like this.
PhotoButton* photoButton = [UIButton buttonWithType:UIButtonTypeCustom];
photoButton.frame = CGRectMake(i, j, thumbSize+2, thumbSize+2);
[photoButton setImage:photoThumb forState:UIControlStateNormal];
[photoButton setAdjustsImageWhenHighlighted:NO];
[photoButton setPhotoButtonPressed:^()
{
[self performSegueWithIdentifier:#"photoSegue" sender:aPhoto];
}];
assigning the block to the photoButton fails at execution with a
-[UIButton setPhotoButtonPressed:]: unrecognized selector sent to instance...
Not sure what I am doing wrong as blocks are new to me. I thought this would be a great way to make a thumbnail image responsive to a touch and then segue to the full sized image in another view controller. Now I'm not sure.
This:
PhotoButton* photoButton = [UIButton buttonWithType:UIButtonTypeCustom];
should be:
PhotoButton* photoButton = [PhotoButton buttonWithType:UIButtonTypeCustom];
You were creating an instance of UIButton, not PhotoButton

UIButton state change does not happen till after touches end

Sorry if this is a basic question, I can't find a definitive answer.
I have set up 4 buttons:
// Add the normal and selected state for each button
UIImage *buttonImage = [UIImage imageNamed:[NSString stringWithFormat:#"HotspotNumber2-%i.png",(hotspotID +1)]];
[hotspotButton setImage:buttonImage forState:UIControlStateNormal];
UIImage *buttonImageSelected = [UIImage imageNamed:[NSString stringWithFormat:#"HotspotNumber2-%is.png",(hotspotID +1)]];
[hotspotButton setImage:buttonImageSelected forState:UIControlStateSelected];
[hotspotButton setImage:buttonImageSelected forState:UIControlStateHighlighted];
[hotspotButton addTarget:self action:#selector(hotspotTouch:) forControlEvents:UIControlEventTouchDown];
And I trap the touch events in the method:
// Called when a hotspot is touched
-(void)hotspotTouch:(id)sender{
// Deselect the hotspot currently selected
if (selectedHotspot) [selectedHotspot setSelected:NO];
selectedHotspot = (UIButton *)sender;
[selectedHotspot setSelected:YES];
// Get dictionary of hot spot that is pressed
NSDictionary *hotspot = [hotspots objectAtIndex:[selectedHotspot tag]];
NSString *imageFileName = [hotspot objectForKey:ksHotspotItemKey];
if ([imageFileName length] > 0) currentImageView.image = [UIImage imageNamed:imageFileName];
}
}
The problem I have is that the highlighted image for the button does not display until the user releases their finger, which is a noticeable delay. I have seen others solve similar issues by changing the background image instead of the button state or performing a selector after a delay so the run loop gets chance to end. Both methods seem like hacks to me and would be grateful if someone could explain what is happening here and what the most robust way of achieving the effect that as soon as the user touches down on the button it changes to its highlighted state.
Thanks in advance,
Dave
Have found a work around. I have created one method for TouchDown and one for TouchUpInside and TouchUpOutside. The TouchDown simply deselects the button if it is already selected and changes my view's image. The TouchUp event sets the selected property of the button. As both the highlighted and selected images are the same the net effect is that the button changes as soon as the button is touched and remains that way after the touch up events. Code is here:
// Called when a hotspot is touched down
-(void)hotspotTouchDown:(id)sender{
// Deselect the hotspot currently selected if it exists
if (selectedHotspot) [selectedHotspot setSelected:NO];
// Get dictionary of hot spot that is pressed
NSDictionary *hotspot = [hotspots objectAtIndex:[sender tag]];
// If the class of the hotspot is 'self' then replace the current image with a new one given in the hotspot data
if ([[hotspot objectForKey:ksHotspotClassKey] isEqualToString:ksHotspotClassSelf]) {
NSString *imageFileName = [hotspot objectForKey:ksHotspotItemKey];
if ([imageFileName length] > 0) currentImageView.image = [UIImage imageNamed:imageFileName];
}
}
// Called when a hotspot is touched up
-(void)hotspotTouchUp:(id)sender{
// Set the selected property of the button
selectedHotspot = (UIButton *)sender;
[selectedHotspot setSelected:YES];
}

Best radio-button implementation for IOS

I would like to ask if there are examples out there on how to implement radio-button options on an iPhone app.
I find the Picker View quite big for a simple selection feature.
I'm not sure if Apple excluded radio buttons on purpose, and whether if it is better to simply use a Picker View from a usability / user experience point-of-view.
I have some thoughts on how the best radio button implementation should look like. It can be based on UIButton class and use it's 'selected' state to indicate one from the group. The UIButton has native customisation options in IB, so it is convenient to design XIBs.
Also there should be an easy way to group buttons using IB outlet connections:
I have implemented my ideas in this RadioButton class. Works like a charm:
Download the sample project.
Try UISegmentedControl. It behaves similarly to radio buttons -- presents an array of choices and lets the user pick 1.
Just want to sum up, there might be 4 ways.
If you don't have much space, add a click event for text or button, then show UIPickerView:
or open a new table view control with a check mark:
If there is more space, add a table view directly to your main view:
The final solution is using UISegmentedControl:
Hope this helps.
Try DLRadioButton, works for both Swift and ObjC. You can also use images to indicate selection status or customize your own style.
Check it out at GitHub.
**Update: added the option for putting selection indicator on the right side.
**Update: added square button, IBDesignable, improved performance.
**Update: added multiple selection support.
I know its very late to answer this but hope this may help anyone.
you can create button like radio button using IBOutletCollection. create one IBOutletCollection property in our .h file.
#property (nonatomic, strong) IBOutletCollection(UIButton) NSArray *ButtonArray;
connect all button with this IBOutletCollection and make one IBAction method for all three button.
- (IBAction)btnTapped:(id)sender {
for ( int i=0; i < [self.ButtonArray count]; i++) {
[[self.ButtonArray objectAtIndex:i] setImage:[UIImage
imageNamed:#"radio-off.png"]
forState:UIControlStateNormal];
}
[sender setImage:[UIImage imageNamed:#"radio-on.png"]
forState:UIControlStateNormal];
}
For options screens, especially where there are multiple radio groups, I like to use a grouped table view. Each group is a radio group and each cell a choice within the group. It is trivial to use the accessory view of a cell for a check mark indicating which option you want.
If only UIPickerView could be made just a little smaller or their gradients were a bit better suited to tiling two to a page...
I've written a controller for handling the logic behind an array of radio buttons. It's open source and on GitHub, check it out!
https://github.com/goosoftware/GSRadioButtonSetController
The following simple way to create radio button in your iOS app follow two steps.
Step1- Put this code in your in viewDidLoad or any other desired method
[_mrRadio setSelected:YES];
[_mrRadio setTag:1];
[_msRadio setTag:1];
[_mrRadio setBackgroundImage:[UIImage imageNamed:#"radiodselect_white.png"] forState:UIControlStateNormal];
[_mrRadio setBackgroundImage:[UIImage imageNamed:#"radioselect_white.png"] forState:UIControlStateSelected];
[_mrRadio addTarget:self action:#selector(radioButtonSelected:) forControlEvents:UIControlEventTouchUpInside];
[_msRadio setBackgroundImage:[UIImage imageNamed:#"radiodselect_white.png"] forState:UIControlStateNormal];
[_msRadio setBackgroundImage:[UIImage imageNamed:#"radioselect_white.png"] forState:UIControlStateSelected];
[_msRadio addTarget:self action:#selector(radioButtonSelected:) forControlEvents:UIControlEventTouchUpInside];
Step2- Put following IBAction method in your class
-(void)radioButtonSelected:(id)sender
{
switch ([sender tag ]) {
case 1:
if ([_mrRadio isSelected]==YES) {
// [_mrRadio setSelected:NO];
// [_msRadio setSelected:YES];
genderType = #"1";
}
else
{
[_mrRadio setSelected:YES];
[_msRadio setSelected:NO];
genderType = #"1";
}
break;
case 2:
if ([_msRadio isSelected]==YES) {
// [_msRadio setSelected:NO];
// [_mrRadio setSelected:YES];
genderType = #"2";
}
else
{
[_msRadio setSelected:YES];
[_mrRadio setSelected:NO];
genderType = #"2";
}
break;
default:
break;
}
}

IBAction used with Dynamically added UIbuttons

Good Evening all!
I have some UIButtons added dynamically into my view and of course I have an IBAction which handles button events.
The problem is: How can I detect which button is pressed if the only thing I know is the (id)sender and the array of buttons?
Buttons are never the same, every button has a different behavior. When I want to use static buttons and connect them through the IB I use something like this :
-(IBAction)doSomething:(id)sender
{
if(sender == button1)
dosomething;
if(sender == button2)
dosomething else;
if(sender == button3)
dosomething3;
}
In my case this does not work because there is no button1, button2, button3 but a MutableArray of buttons which have the same name as they were allocated with it. Button!
I tried using the way above but with no success and i tried also getting the tag of a button but I have nothing to compare it to!
I would really appreciate your help.
sincerely
L_Sonic
PS Dynamicaly means that i am creating the buttons in random time during run time like this
-(void)configActionSheetView
{
buttonView = [[UIView alloc]initWithFrame:CGRectMake(0.0,460, 60, 480)];
[buttonView setBackgroundColor:[UIColor blackColor]];
[buttonView setAlpha:0.6];
for (int i = 0 ;i<[buffButtons count];i++)
{
UIButton *customButton = [buffButtons objectAtIndex:i];
customButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//UILabel *customLabel = [[UILabel alloc]init];
//[customButton setTag:(i)+11];
[customButton addTarget:self action:#selector(activateBuffEffect:) forControlEvents:UIControlEventTouchUpInside];
[customButton setAlpha:1.0];
customButton.frame = CGRectMake(8.0, 5+(50*i), 44.0, 44.0);
[customButton setTitle:nil forState:UIControlStateNormal];
buttonView.frame = CGRectMake(0, 460, 60, 50+(44*(i+1)));
[buttonView addSubview:customButton];
}
}
this is inside a functions and gets called during run time. the buffButtons is a mutableArray with buttons that gets populated during runtime.
i need a solution like this i cannot get a different eventhandling method for everybutton.
When you was "added dynamically" I assume you mean that they are created from some piece of code. Since all buttons to different things and you know what a certain button should do, why don't you add different actions to different buttons?
UIButton *myCreatedButton = [[UIButton alloc] init];
[myCreatedButton addTarget:self
action:#selector(doSomething:)
forControlEvents:UIControlEventTouchUpInside];
UIButton *myOtherCreatedButton = [[UIButton alloc] init];
[myOtherCreatedButton addTarget:self
action:#selector(doSomethingElse:)
forControlEvents:UIControlEventTouchUpInside];
In the above code the target (set to self) is the class where the method you want to run is found, the action is the method that you want to run and the controlEvent is what should cause the method to run.
If you did it like this you would split the code in different methods like these (you do not need to specify them in the header):
-(void)doSomething:(id)sender {
// do somthing here ...
}
-(void)doSomethingElse:(id)sender {
// do somthing else here ...
}
This way you don't need to know what button was pressed since the correct code would get called anyway. Besides it makes it cleaner if you need to change the code for some of the buttons.
Found it!
-(IBAction)buttonTapped:(id)sender {
UIButton *btn = (UIButton *)sender;
NSLog(#"tapped: %#", btn.titleLabel.text);
[self anotherIBAction:sender];
}
now i can get the tag from the btn :D
thnk you!
Why not add a tag the button and then get the tag number from (id)sender in the selector function?