I have a simple question about event handling in iOS applications... suppose you have an app with some buttons that react to the TouchUpInside event calling the same action, what is the best way within the action method to understand what is the button that triggered the event? I know that it can be easily done using the title of the button, but I think it is not the best way if you have a localized app in which button text may change (unless it is possible to reverse the localization of the title, i.e. retrieve the original string from a localized string)... is there a good practice about this topic? Should I use some other property of buttons to distinguish among different buttons?
Thank you in advance for any help.
There is something called a "Tag" that you can set for UIButtons, or anything that can respond to an event for that matter. If you are using Interface Builder, click the attributes inspector for the item and select a value for the tag (integer). In your code do something like this...
...
- (IBAction)buttonReceived:(id)sender
{
if ([sender tag] == 1) {
//Do something
}
else if ([sender tag] == 2) {
//Do something else
}
}
In addition to the tag property, or just in case you are already using the tag for some other purpose that would mean duplicate tag values for one or more different buttons, you can always set up an IBOutlet ivar to each button you needed to check, and then in the IBAction, do something like this:
- (IBAction)buttonReceived:(UIButton *)sender
{
if (sender == myButtonA) {
// processing for button A
}
else if (sender == myButtonB) {
// processing for button B
}
}
It is a bit more work, but it can come in handy at times.
Related
Initially I had two buttons with titles: "+" and "-". Both buttons are located in table cell. I have used protocol and delegate to pass value from button title to function call which depends on input params. If input parameter is "-" - decrease value, if "+" - increase.
But later I removed titles and replaced buttons with respective images. And here I faced an issue - I cannot call function properly because title is blank.
I have implemented the following workaround. I have set Accessibility Identifier for both buttons. For example for +:
And in cell class I used accessibilityIdentifier:
#IBAction func didPressOrderCellButton(_ sender: UIButton) {
cellDelegate?.didPressOrderCellButton(order: order!, menuItem: menuItem!, action: sender.accessibilityIdentifier!)
}
But... I have some doubts if it's proper way to do this. Will it create any issues in future if I decide to work with accessibility feature?
I do not want to use title and add code to ViewController class to hide it every time view is loaded or appeared. I want to avoid such solutions in my code because it's too difficult to support such solutions I believe.
I have tried to find another button identifier that I can use, but didn't succeed.
The simple approach would be just set the tag value inside your button and then check the same tag value and perform your operation Plus or Minus accordingly.
For instance:-
if sender.tag == 0 {
//Do minus
} else if sender.tag == 1 {
//Do plus
}
I have a custom UIControl subclass with an action method callback. I want to display the value of the control element on a UILabel while it is being adjusted, and then I want the label to become hidden when the user stops adjusting the control.
Therefore, I have connected the action for both UIControlEventValueChanged and UIControlEventTouchUpInside. Both successfully invoke my action method. However, to do different things in this method based on the action I need to know which event triggered the method. How can I do this? I've looked through UIControl and don't see an obvious property. state seems to return 1 for both actions.
So something like this:
- (void)handleSlider1:(CustomSlider*)sender {
if (sender.state == UIControlEventValueChanged) {
// code
} else {
// different code
}
}
You can distinguish the two events pretty easily by connecting them each to separate IBActions. Each new action then would call your single handler, passing the appropriate UIControlEvent value along:
- (IBAction)sliderValueChanged:(CustomSlider *)slider
{
[self handleSlider1:slider forEvent:UIControlEventValueChanged];
}
- (IBAction)sliderValueChanged:(CustomSlider *)slider
{
[self handleSlider1:slider forEvent:UIControlEventTouchUpInside];
}
- (void)handleSlider1:(CustomSlider *)sender forEvent:(UIControlEvents)event
{
if (event == UIControlEventValueChanged)
//...
}
If you want to use the same method to handle both events then you can check the highlighted property of the control:
if (sender.highlighted) {
// slider is changing value (value changed)
} else {
// slider has stopped changing value (touch up inside)
}
Alternatively, you could simply create two separate action methods and connect each event to the required method.
I'm learning OBJ.C/Xcode/Cocoa here and have run into a question I can't seem to find an answer for.
I want the text in a UILabel to switch between two states (ON/OFF for example) each time the user clicks the same button.
I can get the label to switch to one state, but can't get it to switch "back" when the user clicks the button again. I am assuming there is some logic required, or checking the status of the object once the button is clicked...
Does this require me to keep track of a bool or the "state" of the Label (or button)?
Would this require two methods to be associated to the button, or can it happen with just one?
Thanks for any guidance/pointing in the right direction/Code snips!!!!
~Steve
I got an answer, and it works:
- (IBAction)flip:(id)sender
{
_flipButton.selected = !_flipButton.selected;
self.flipLabel.text = (_flipButton.selected) ? #"ON" : #"OFF";
}
- (IBAction)flip:(id)sender {
[yourButton setSelected:!yourButton.selected];
self.flipLabel.text = (yourButton.selected) ? #"ON" : #"OFF";
}
This toggles the selected state of the button then checks its state to determine which string to pass to the text property of your label.
the easiest way (I think) is to store a BOOL with the state of the UILabel and (on each click of the button) negate the BOOL and set the appropriate text of the Label
You could call this: yourLabel.enabled = !yourLabel.enabled on button click to change the enabled-state of your UILabel. Or what kind of state do you mean ?
I have this UISwitch that I connected from my storyboard to my controller.
#property (weak, nonatomic) IBOutlet UISwitch *wantHelp;
What I am trying to do is to configure it so that the app can know when the state of the uiswitch has changed.
I looked at examples online and they show something similar to this:
-(IBAction)helpToggle:(id)sender
{
if (wantHelp.on)
{
NSLog(#"yes");
}
else
{
NSLog(#"No");
}
}
but they seem to refer to different ids like the wantHelp or the helpToggle and many of the examples use this kind of a heading -(IBAction)helpToggle:(id)sender but I am confused what the "sender" is configured from and what it should be in my case.
Thanks for your help in helping me understand what to do.
sender is the object that's sending the message. If you have your UISwitch hooked up to send a helpToggle: action to an object that implements it, sender will be a pointer to the switch.
If you want to check it out for yourself, add a line like this to your code:
`NSLog(#"sender is: %#", sender);`
Every time you flip the switch (wantHelp), the method helpToggle is called. When helpToggle is called, the if statements check if the conditions are true, in this case (wantHelp.on). If wantHelp is on, then the code within that if statement is called, otherwise the else statement is called.
As for the sender tag, it's what allows for communication for the method back to the switch I believe.
Usual:
Object > Method
Sender:
Object > Method > Back to Object
We have a iPad app which includes a two-column news reader. The left view contains the list of news of which some link directly to a news and some push another view controller with another list of news. This will also cause a UIButton to be set as the leftBarButtonItem of the navigation bar. If we are on first level, a simple image that cannot be tapped will be the leftBarButtonItem.
My goal is now to have a test that taps every news on the first level. If a news leads to a second level list, it should tap the UIButton in the navigation bar.
How can I check, if the leftBarButtonItem is "tappable"? Since it can be either an image or a button, just calling navigationBar().leftButton().tap() will lead to an error if it's an image.
I'm also using the tuneup library if that's any help.
Almost all elements in UIAutomation could be tapped. It does not matter if it is an Image, View or a Button. You will get an error in case an object you are trying to tap is invalid.
How to check:
if ( navigationBar().leftButton().checkIsValid() )
{
navigationBar().leftButton().tap();
}
else
{
//do what you need.
}
or you can check if an object you are trying to tap is a button, for example (not the best way but it works):
if ( navigationBar().leftButton().toString() == "[object UIAButton]" )
{
navigationBar().leftButton().tap();
}
else
{
//do what you need.
}
checkIsValid() is available for all UI elements. It will return true if an object exists.
toString() will return [object UIAElementNil] if element is invalid or will return [object UIAButton] or [object UIAImage].
Also try to use Apple documentation:
http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Reference/UIAElementClassReference/UIAElement/UIAElement.html
You can simply use
if (navigationBar().leftButton().exists)
{
navigationBar().leftButton().tap();
}
else
{
//do what you need.
}