UISegmentedControl buttons stop working - ios

My iOS app has a form with about a dozen fields and I wanted to add "Previous"/"Next" buttons above the keyboard to help users move between fields. I have something like this:
for (UITextField *t in _textfields) {
t.delegate = self;
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
UISegmentedControl *segControl = [[UISegmentedControl alloc] initWithItems:#[#"Previous", #"Next"]];
[segControl addTarget:self action:#selector(switchTextField:) forControlEvents:UIControlEventValueChanged];
segControl.segmentedControlStyle = UISegmentedControlStyleBar;
segControl.tag = [_textfields indexOfObject:t];
if (segControl.tag == 0) [segControl setEnabled:NO forSegmentAtIndex:0];
else if (segControl.tag == [_textfields count] - 1) [segControl setEnabled:NO forSegmentAtIndex:1];
[segControl sizeToFit];
UIBarButtonItem *segItem = [[UIBarButtonItem alloc] initWithCustomView:segControl];
UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self.view action:#selector(endEditing:)];
[toolbar setItems:#[segItem, flexButton, doneButton]];
[toolbar sizeToFit];
[t setInputAccessoryView:toolbar];
}
The problem I'm having is that every so often one of the segments stops working. The method switchTextField just does not get called, the button looks normal, not disabled, but the touches do not register. Sometimes it's the "previous" button, sometimes it's the "next" one, never both at the same time, and sometimes they both work fine. Once one of the buttons gets stuck, the only way to (temporarily) fix it is to tap another textfield without the use of the toolbar or dismiss the keyboard and start editing again. What could be the problem?

A segmented control is not a good choice when you really want the behavior of a UIButton for your prev/next controls.
What I think is happening is that you are initializing the toolbar with the segmented control and no segment selected. So when you tap prev/next the first time, the value changes and that segment is selected for that specific segmented control. As you continue to tap prev/next, eventually you get to a segmented control that already has a segment selected and that segment will not fire a value changed event when tapped because it is already the selected segment.
You can explicitly deselect the selected segment in your switchTextField: method (make sure you don't trigger switchTextField: recursively) or you can change your implementation to use UIButton objects for prev/next instead of the segmented control.
I recommend going with UIButton.

Related

ios hide text of left navigation button

I need to show only arrow button and hide text of left navigation button. According to this link, I can do like this. But if I do like that, slide to go back feature will be destroyed.
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil];
So, I use like this to hide text.
self.navigationController.navigationBar.topItem.title = #"";
So far, it is okay. However, if my previous view's searchDisplayController is active and push to new view,it show left navigation button text. May I know how to do?
Copy and paste this line in every view controller:
self.navigationController.navigationItem.leftBarButtonItem.title = " "
Alternatively you can achieve this in storyboard/xib files using the following steps:-
Drag and drop a Navigation Item from object library onto your ViewController. Then select the ViewController.
Select that Navigation Item in the menu on left side(it will the one with back arrow and Title as text: "< Title").
Select Attribute Inspector on the right hand side and replace text: Title with an empty space.
Repeat these steps for all the the view controllers.
Hope it helps.
One solution you will have to add custom button for your requirement like this:
//create image instance add here back image
UIImage *imgBack = [UIImage imageNamed:#"image name here"];
//create UIButton instance for UIBarButtonItem
UIButton *btnBack = [UIButton buttonWithType:UIButtonTypeCustom];
[btnBack setImage:imgBack forState:UIControlStateNormal];
btnBack.frame = CGRectMake(0, 0, imgBack.size.width,imgBack.size.height);
[btnBack addTarget:self action:#selector(btnBackAction:) forControlEvents:UIControlEventTouchUpInside];
//create UIBarButtonItem instance
UIBarButtonItem *barBtnBackItem = [[UIBarButtonItem alloc] initWithCustomView:btnBack];
//set in UINavigationItem
self.navigationItem.leftBarButtonItem = barBtnBackItem;
Button method given below:
-(void)btnBackAction:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
EDIT : For slide swipe add in viewDidLoad method
//for enabling swipe gesture
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
#Atif's answer is correct. I just want to add in that, instead of copying and pasting the code in all files, create a custom UINavigationController and implement the required code as mentioned by #Atif.(I cannot comment due to low rating.)

iOS 7.1 update hide navigation bar left button by default

I have following code to create UINavigationBar and set the navigation item with a back button at the right side.
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 60)];
navBar.delegate = self;
UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleDone target:self action:#selector(backButtonTapped)];
UINavigationItem *backItem = [[UINavigationItem alloc] init];
[backItem setTitle:#"What's New"];
[backItem setLeftBarButtonItem:back];
backItem.leftBarButtonItem.enabled = YES;
[navBar pushNavigationItem:backItem animated:NO];
[self.view addSubview:navBar];
This worked perfectly until i update my xCode 5 to iOS 7.1 update recently.
But now when the UIView presented the navigation button is not visible. But when i touch the location of the button (where it used to be before the update), it shows me the button and click even is firing.
My question is how to set the button visible at the moment view is present to user ?
Thank you.
Try to initialize your UIBarButtonItem with initWithCustomView. Also, try to set buttonType of the UIButton to UIButtonTypeSystem.
Thanks to all,
finally what happen is as follows.
The above behaviour is not what i assume it is. When a new view is loaded the button is disappear by default and only if i move my finger here & there on the location button used to be it appears. Further when i keep the view still, after it loaded, about 15 seconds, button appears.
So i suspect this is with "viewDidLoad" method. (Code related to this UINavigationBar is in viewDidLoad method.
When I move above code to "viewDidAppear" method it start to work again.

Navigation through the textfields which are each inside successive tableView cells?

I am using a tableView Controller and in it I have 4 sections. 1st section contains 2 textfields, 2nd one has 4 textfields, 3rd one has 7 and so on. The problem which I am facing is that I am not able to navigate through the textfields by pressing the next and previous buttons on the keyboard. Actually I have tried a lot of open source libraries to put "Next" and "previous" button on a toolbar above the keyboard but not been able to do so. Every time the keyboard loads there is no toolbar above it.
Maybe It is due to the textfields inside the tableview cell.
Can anybody suggest me the solution to do that.
Try:
UIToolbar* toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
toolbar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *barItem = [[UIBarButtonItem alloc]initWithTitle:#"Previous" style:UIBarButtonItemStyleDone target:self action:#selector(prev)]
toolbar.items = [NSArray arrayWithObjects:[[UIBarButtonItem alloc]initWithTitle:#"Next" style:UIBarButtonItemStyleDone target:self action:#selector(nextTF)],barItem,nil];
[toolbar sizeToFit];
self.yourTextField.inputAccessoryView = toolbar;
Next do:
-(void)prev
{
//previous
}
-(void)nextTF
{
//next
}

Custom Button initWithImage displaying a default button behind the custom image

I am trying to make a button for my navigation bar with a custom image. When I run the following code, the button appears as it should, except you can see another wider button behind it, sticking out the sides. How do I get rid of that other button?
UIBarButtonItem *emailButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"emailBut"]
style:UIBarButtonSystemItemCompose
target:self
action:#selector(emailSheet)];
self.navigationItem.rightBarButtonItem = emailButton;
Hmm... UIBarButtonSystemItemCompose is a system icon, so I guess you are probably overlaying your icon on top of it. You should instead use UIBarButtonItemStylePlain (or other styles) for your style: argument.
Edit:
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(...)];
[button setBackgroundImage:someImage];
[button addTarget:self action:#selector(something:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
[self.navigationItem setRightBarButtonItem:barButtonItem];
Ok, for some reason initWithImage only puts the image in the center of a default button. The fix was to initWithCustomView as iBlue suggested.
Another thing to note is that the barBackButton doesn't allow custom views, so I had to make that one a leftButton instead of a backButton, with my own go back method. I hope Apple makes this easier in the future.

How do I specify an action for a custom Back button in a standalone UINavigationBar?

I have a custom UINavigationBar on a screen, i.e., no navigation controller, as defined below which contains a Back button w/ the title "Media" and the action "mediaViewComplete". However, the mediaViewComplete method is not being called when the button is tapped. How do you specify an action for a Back button?
self.navigationBar=[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
navigationBar.barStyle=UIBarStyleBlackTranslucent;
UINavigationItem *navigationItem=[[UINavigationItem alloc]init];
UIBarButtonItem *backButton=[[UIBarButtonItem alloc]initWithTitle:#"Media" style:UIBarButtonItemStylePlain target:self action:#selector(mediaViewComplete)];
navigationItem.backBarButtonItem=backButton;
[self.navigationBar pushNavigationItem:navigationItem animated:NO];
navigationItem=[[UINavigationItem alloc]init];
UIBarButtonItem *editButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editCategorization)];
navigationItem.rightBarButtonItem=editButton;
[self.navigationBar pushNavigationItem:navigationItem animated:NO];
[self.view addSubview:navigationBar];
[editButton release];
[backButton release];
[navigationItem release];
The problem is that you are using:
navigationItem.backBarButtonItem = backbutton;
The backBarButtonItem has it's own event that is not overridden by your action: option. In fact, Apple guidelines state that you should use "nil" as you action for backBarButtonItem. The backBarButtonItem is not owned by the current view controller.
If you are unconcerned about the arrow shape of the button, you should use leftBarButtonItem instead. If you want to create fully custom back buttons with the arrow shape, you'll have to do some custom magic. Luckily, most of the work has been done for you:
http://idevrecipes.com/2011/01/12/how-do-iphone-apps-instagramreederdailybooth-implement-custom-navigationbar-with-variable-width-back-buttons/
Download this project and look at the results. It even contains the images you need to retain an arrow shaped custom back button. It is more work, but it's much less hack.

Resources