I've searched this for a while but can't find anything quite the same.
I have a UITableView, and when a certain row is selected, I insert another row below.
The inserted row is a custom tableviewcell which hold a UIPickerView.
The pickerview works fine, and when an item is selected it can trigger the notification, sending selected info back to the tableviewcontroller, and then remove the "pickerviewcell". All good there.
But this isn't ideal if the user wants to scroll back and forth on the uipickerview. So I've added a uitoolbar to the uipickerview with a Cancel & Done button.
But the Cancel and Done buttons never get fired.
From other items I have read, they talk about UIFirstResponder etc etc, but they are all related to making the uipickerview an inputaccessoryview for a uitextfield. But that is not what I am doing.
I've tried doing it all in code and via Storyboards, with the same results each time.
Some example below..
// (in my CustomTableViewCell's AwakeFromNib function)
let screenSize: CGRect = UIScreen.mainScreen().bounds
pickerView = UIPickerView(frame: CGRectMake(0,0, screenSize.width, 162))
pickerView.delegate = self
pickerView.dataSource = self
pickerToolbar.barStyle = UIBarStyle.Default
pickerToolbar.translucent = true
pickerToolbar.tintColor = UIColor.orangeColor()
pickerToolbar.sizeToFit()
pickerToolbar.userInteractionEnabled = true
pickerView.addSubview(pickerToolbar)
self.contentView.insertSubview(pickerView, atIndex: 3)
// both these logs show correct output
NSLog("picker subviews: %#", pickerView.subviews.description)
NSLog("toolbar subviews: %#", pickerToolbar.subviews.description)
Screenshot example:
By clicking on the "To" cell, the new cell is inserted which has the picker. The picker works fine by itself. But the Cancel button doesn't get triggered. It has an IBAction linked to it from Storyboard.
Clicking any cell also closes/removes the pickercell correctly.
I have made a picker within a UITextview and I using
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return NO;
and then dismissing the keyboard with
-(void)dismissKeyboard {
[_date resignFirstResponder];
}
where _date was my UITextfield property
Dismissing UIPickerView with Done button on UIToolBar
this is a really good post I found on this topic as well! I hope it helped.
Related
My functionality is to open picker on click of textField. My textfield is inside scrollview is shown in below image.
I want to disable userinteraction of scrollview when picker opens. Following is my code.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[self.picker removeFromSuperview];
[self.toolBar removeFromSuperview];
textField.inputView = self.picker;
textField.inputAccessoryView = self.toolBar;
self.scrollview.userInterationEnabled = NO;
return YES;
}
When I comment the userInteractionEnabled code. Picker is opening perfectly. But when I uncomment code picker is not opened.
Also I gave some delay for this code. so after dalay my picker is hidden again.
The problem here is that userInteractionEnabled is inhereted from the scrollView to the textField. And as it is explained here
A UITextField will also refuse to become first responder if its userInteractionEnabled property is NO as I just discovered. I had to explicitly re-enable user interaction on the text field before it would accept first responder status.
And it can not show the inputView of the textField.
You shou ensure that your textField userInteracationEnables is true or to move the pickerView outside of the textField.inputView.
You can use this cool customizable control for having picker as an inputView on textfield.
Or this one if you want to disable the interaction to background view while picker is open.
In my app I have a UITableViewCell with a UITextField in it. When the user starts typing in this textfield, an autocomplete view appears.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (self.suggestions != nil) {
self.autocomplete = [[AutoComplete alloc] initWithFrame:CGRectMake(10, 53, self.frame.size.width-20, 200)];
self.autocomplete.delegate = self;
self.autocomplete.suggestions = self.suggestions;
[self addSubview:self.autocomplete];
[self bringSubviewToFront:self.autocomplete];
}
return YES;
}
This is nothing more than a UIView with a UITableView inside it. However, what happens is that this view is hidden behind the section header and the next cell.
So while it appears to be inserted above the cell, it registers the tapp below it. When you click in the autocomplete it registers the click in the next cell. How can I fix this?
Your issue is you are adding it to the view and not the tableview which resides in the UIView as well as having a section header that will probably block it out as well. I see your y position is only 53, so your header is likely blocking it out.
I am not 100% sure where you want your result to be viewed and used, that's not clear in your question. If you want your view to be above everything else you could:
"I have a UITableViewCell with a UITextField in it. When the user starts typing in this textfield, an autocomplete view appears." - add the result view to your cell, not the main view; [cell.contentView addSubview...
Shift your tableview down by changing it's y position to self.autocomplete.view.frame.size.height. Add a nice little animation to it as it changes position too, always something that bit extra.
Consider adding it as a subview to your TableView and bringing to front, should work.
(little bit extra on the cell.contentView)
I have a table view with custom cells, each cell contains a textField. When the user tap on the textfield a UIPickerView will be displayed. I have this approach already done and work good. The thing is, the picker should display different data depending on which textField has been tapped, how can I detect this?
What I've done:
In viewDidLoad I create a view property which contains a UIPickerView.
In cellForRowAtIndexPath: I assign that view with the picker as an inputView for the textField (I did it this way to avoid creating a picker everytime a cell is rendered)
Ok, I found a solution that works really smooth:
I disabled the textField on every cell
I stop adding the picker as an inputView in cellForRowAtIndexPath
Once the user tap on didSelectRowAtIndexPath (which is called when they tap on the textField) I do the following:
if ([dataInfo[indexPath.row] isEqualToString:#"Accessibility"]) {
pickerItems = accessibilityItems;
}
else if ([dataInfo[indexPath.row] isEqualToString:#"Floor"]){
pickerItems = floorItems;
}
[picker reloadAllComponents];
SubCellTableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
[cell.subcellSubtitleTextField setEnabled:YES];
cell.subcellSubtitleTextField.inputView = viewContainingPicker;
[cell.subcellSubtitleTextField becomeFirstResponder];
I hope this can help someone else!
I'm trying to achieve a similar keyboard interaction that Messages has in iOS 7. I have a UIView which contains a UITextView, and when the user selects it to start typing, I want to make this UIView the inputAccessoryView. This would take care of the animation for me, as well as the new UIScrollView keyboard dismiss interaction in iOS 7.
When the UITextView begins editing, I'm trying to set its inputAccessoryView to its parent UIView (which is already in the view hierarchy). The keyboard appears but not with an accessory view.
I've read some people are using a duo of UITextFields to make this work, but that seems like a bad way to achieve this.
Any suggestions?
A much easier solution is to make your input field the input accessory view of your view controller:
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (UIView *)inputAccessoryView
{
return self.yourInputField;
}
The view will be on screen at the bottom of the screen and when it becomes first responder in response to a user tapping it, the keyboard will be presented. The view will be animated such that it remains immediately above the keyboard.
The only way to get this to work is via a second text field. The idea is to make it a subview but not visible (due to crazy rect). You then switch firstResponder back and forth between it and the real text field while its getting delegate methods. I created a some one viewController test project and did this (you can copy paste and verify behavior with about 2 minutes of time):
#implementation ViewController
{
UITextField *field;
UITextField *dummyView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
field = [[UITextField alloc] initWithFrame:CGRectMake(0, 460, 320, 20)];
field.borderStyle = UITextBorderStyleRoundedRect;
field.delegate = self;
//field.inputAccessoryView = field;
field.text = #"FOO";
[self.view addSubview:field];
dummyView = [[UITextField alloc] initWithFrame:CGRectMake(0, 40000, 320, 20)];
dummyView.delegate = self;
[self.view addSubview:dummyView];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField == field && textField.superview == self.view) {
[field removeFromSuperview];
dummyView.inputAccessoryView = field;
[dummyView becomeFirstResponder];
}
return YES;
}
#end
I should add I've used this technique in shipping apps since iOS 4.
EDIT: So a couple of other ideas:
1) To make the glitch when the keyboard starts moving look a little better, you could take a snapshot of your textView, put that into a UIImageView, and when you remove the textView from the primary view, replace it with the UIImageView. Now the appearance is the same. Add an animation for the image so that noting happens for 50 ms, then the alpha goes to 0. Add a similar animation to your real textview, so that it has an alpha of 0 for 50 ms, then it goes to 1. You may be able to tweak this so the transition is good (but not great).
2) The way apple probably does this is to get the animation curve and timing from the keyboard moving notification. In this case they would add a accessory view with 0 height at first, and animate the textField so its tracking the keyboard, but above it. Both moving same distance at the same time. At the end of the animation, the textField is pulled out of self.view, the accessory view has its frame changed to have the height of the textField, and the textField is placed as a subview of the accessory container view. This should work but yeah, its a bit complex to do. If you want someone to code it for you offer a 100 pt bounty. You still need the dummy text field for when you go and move the textField at the end, since when you take it out of its containing view it will resign first responder. So at the end, you make the dummy field the first responder, move the textfield, then make the real textfield the first responder again.
This actually works best if you don't use .inputAccessoryView at all and instead just animate the position of the parent UIView as the keyboard opens and closes. Here is an answer describing the process step-by-step with all the code.
I have a UITableViewController that show data in cells. In viewWillAppear I add a UIView to tableHeaderView with this method self.tableView.tableHeaderView =headerView;
In headerView I add a UISearchBar and a UISegmentControl programmatically. I set UISearchBar delegate like this
self.searchDisplay.delegate = self;
self.searchDisplay.searchBar.delegate = self;
self.searchDisplay.searchResultsDataSource = self;
self.searchDisplay.searchResultsTableView.delegate = self;
the searchDisplay is UISearchDisplayController.
The search is work perfectly but my problem is when I select one cell from searchResultsTableView and go to another viewController when touch back button in UINavigationController and come back to this view the table doesn't scroll anymore.
I add this two method in viewDidLoad and viewWillAppear but still doesn't work
self.tableView.bounces = YES;
self.tableView.scrollEnabled = YES;
It's work perfectly when I select one row from table without search and go and come back.
What's the problem ?
You are actually using two tableviews on the view, (self.tableView and self.searchDisplay.searchBarTableView) one for showing data, and one for showing the searched data. I think the searchViewController is staying on the screen after the segue.
There's a trick to show the whole data and search results in a single tableView (no need to use UISearchDisplayController)
Just do the following to show the search results:
self.tableView.dataSource = self;
self.tableView.delegate = self;
for the actual data, you can empty the UISearchBar and load the whole data in table view datasource.
Try placing your
self.tableView.bounces = YES;
self.tableView.scrollEnabled = YES;
in - (void) viewWillAppear:(BOOL)animated instead of viewDidLoad. I believe viewDidLoad doesn't get called when coming back from a other view, only when being created.