In my first ViewController, I make one UITextField to becomeFirstResponder, and the focus stay that TextField and keyboard appear automatically. It just works fine. But then I present another child ViewController which has 3 UITextFields (A,B,C) in this ViewController, I set the first UITextField (say A) to becomeFirstResponder in this child ViewController, the focus stay the A but the keyboard doesn't appear. I searched all the answers the whole day, but nothing found.
Here is the code.
in parent VC, I set:
TestVC *testVC= [[TestVC alloc] init];
testVC.modalPresentationStyle=UIModalPresentationFormSheet;
[detailvc presentViewController:testVC animated:NO completion:nil];
in child VC TestVC, I set:
UITextField *v_matcode=[MyViewUtil addTextField:#"" x:10 y:10 width:100 height:40];
[self.view addSubview:v_matcode];
[v_matcode becomeFirstResponder];
and this is the addTextField():
+(UITextField *) addTextField:(NSString *)text x:(int)_x y:(int)_y width:(int)_width height:(int)_height {
UITextField *v_txt = [[UITextField alloc] init];
v_txt.frame= CGRectMake(_x, _y, _width, _height);
v_txt.borderStyle = UITextBorderStyleRoundedRect;
return v_txt;}
The v_matcode has the focus, but the keyboard doesn't appear. But if I don't set this textfield becomeFirstResponder and let user tap it,the keyboard appear correctly. Why is that?
try setting animated to YES
[detailvc presentViewController:testVC animated:YES completion:nil];
Related
I am loading a ABPeoplePickerNavigationController on the click of a UITableViewCell.
self.peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
self.peoplePicker.peoplePickerDelegate = self;
[self.peoplePicker setDelegate:self];
self.peoplePicker.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:self.peoplePicker animated:YES completion:nil];
When the picker is presented as UIModalPresentationFormSheet, I want to disable the UIViewController behind it. For that I could load a transparent view on presenting the picker and dismiss it when the picker is dismissed. So the tap on the viewcontroller wont work.
I would like to know if there is another way to do it, where I wouldn't require to create a new UIView and load/dismiss it.
You can setUserInteractionEnabled property on the view of the ViewController before presenting and after dismissing the Picker view.
I have this code in my viewdidload:
[_txtName setDelegate:self];
[_txtName becomeFirstResponder];
_txtName.enabled = YES;
_txtName.text = #"";
But when my view loads, the keyboard does not show, any idea why?
_txtName is the UITextField
As pointed out in a comment by #lukya you should place the call to becomeFirstResponder in either viewWillAppear: or viewDidAppear:. If you place the call in viewWillAppear: the keyboard will be shown on screen when the view is shown. If you would like the keyboard to animate in from the bottom when the view appears you should put the call in viewDidAppear:.
I know the SDK documentation says
Taps outside of the popover’s contents automatically dismiss the popover.
But I'm sure the smart people here found a way :)
maybe I should overwrite the popover dismiss function?
Thanks
EDIT:
I tried using the passthroughViews as was suggested here, and it works perfectly. Here's the code for whoever needs it - in this example, I put self.view in the array, which means that where ever outside the button where the popover was originated, nothing dismiss the popover.
popoverController.passthroughViews = [[[NSArray alloc] initWithObjects:self.view, nil] autorelease];
You need to set the passthroughViews property. From the documentation:
An array of views that the user can interact with while the popover is visible.
#property (nonatomic, copy) NSArray *passthroughViews
When a popover is active, interactions with other views are normally disabled until the popover is dismissed. Assigning an array of views to this property allows taps outside of the popover to be handled by the corresponding views.
Set passthroughViews to an array of view(s) that you want to handle the touch event instead of just dismissing the popover.
There is a very simple and legit solution. In the view controller that presents your UIPopoverController, conform to the UIPopoverControllerDelegate protocol and implement the following delegate method. I just tested this and it does prevent popover to dismiss.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
Just make sure that you have set the delegate of your popover controller to the view controller that implements this.
You can dismiss the popover by using [popoverController dismissPopoverAnimated:NO]; method.
The accepted answer does not really answer the question, "is there a way NOT to have the popover dismissed when pressing outside it?", imo. It does give a possible view but could require hackish access to all parent views and determining what views are on the screen etc. The question could be rephrased as, "how do I make a popover view modal?"
You would do this like so, with a done button to close the popover:
UIViewController* vc = [[[UIViewController alloc] init] autorelease];
UIBarButtonItem* doneButton = [[[UIBarButtonItem alloc] initWithTitle:#"Done"] style:UIBarButtonItemStyleDone target:self action:#selector(processDoneAction)] autorelease];
[vc.navigationItem setLeftBarButtonItem:doneButton];
vc.modalInPopover = YES;
//If you want full screen:
vc.modalPresentationStyle = UIModalPresentationFullScreen;
vc.wantsFullScreenLayout = YES;
UINavigationController* navC = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease];
UIView* view = create your view
vc.view = view;
UIPopoverController* pc = [[[UIPopoverController alloc] initWithContentViewController:navC] autorelease];
pc.delegate = self;
self.popoverController = pc;
Then you'll in your processDoneAction method you will need to dismiss the popover. Other considerations would be dismissing and redisplaying on device orientation changes, but I will leave that to another exercise as that has been answered previously on stackoverflow.
I have a core data application which uses a navigation controller to drill down to a detail view and then if you edit one of the rows of data in the detail view you get taken to an Edit View for the that single line, like in Apples CoreDataBooks example (except CoreDataBooks only uses a UITextField on its own, not one which is a subview of UITableViewCell like mine)!
The edit view is a UITableviewController which creates its table with a single section single row and a UITextfield in the cell, programatically.
What I want to happen is when you select a row to edit and the edit view is pushed onto the nav stack and the edit view is animated moving across the screen, I want the textfield to be selected as firstResponder so that the keyboard is already showing as the view moves across the screen to take position. Like in the Contacts app or in the CoreDataBooks App.
I currently have the following code in my app which causes the view to load and then you see the keyboard appear (which isn't what I want, I want the keyboard to already be there)
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[theTextField becomeFirstResponder];
}
You can't put this in -viewWillAppear as the textfield hasn't been created yet so theTextField is nil. In the CoreDataBooks App where they achieve what i want they load their view from a nib so they use the same code but in -viewWillAppear as the textfield has already been created!
Is there anyway of getting around this without creating a nib, I want to keep the implementation programatic to enable greater flexibility.
Many Thanks
After speaking with the Apple Dev Support Team, I have an answer!
What you need to do is to create an offscreen UITextField in -(void)loadView; and then set it as first responder then on the viewDidLoad method you can set the UITextField in the UITableViewCell to be first responder. Heres some example code (remember I'm doing this in a UITableViewController so I am creating the tableview as well!
- (void)loadView
{
[super loadView];
//Set the view up.
UIView *theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = theView;
[theView release];
//Create an negatively sized or offscreen textfield
UITextField *hiddenField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, -10, -10)];
hiddenTextField = hiddenField;
[self.view addSubview:hiddenTextField];
[hiddenField release];
//Create the tableview
UITableView *theTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStyleGrouped];
theTableView.delegate = self;
theTableView.dataSource = self;
[self.view addSubview:theTableView];
[theTableView release];
//Set the hiddenTextField to become first responder
[hiddenTextField becomeFirstResponder];
//Background for a grouped tableview
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Now the the UITableViewCells UITextField has loaded you can set that as first responder
[theTextField becomeFirstResponder];
}
I hope this helps anyone stuck in the same position as me!
If anyone else can see a better way to do this please say.
Try do it in viewDidAppear method, works for me.
I think the obvious solution is to create the textfield in the init method of the view controller. That is usually where you configure the view because a view controller does require a populated view property.
Then you can set the textfield as first responder in viewWillAppear and the keyboard should be visible as the view slides in.
have you tried using the uinavigationcontroller delegate methods?:
navigationController:willShowViewController:animated:
Editable TextView with Second NavBar - Text appears, but too late.
The app has a single Navigation Controller.
I have an iPhone App that has basically three levels.
Level 1 - Table with category Names
Level 2 - Table with list of items for selected category
Level 3 - Tabbed View with several views, including UITextView for details of item
One to these Tabbed Views with a TextView is editable.
When the user taps in the editable TextView the KeyBoard
appears. User can type in the TextView. Characters appear
as they are typed.
At the top of this Level 3 TextView there is a NavBar (present for all 3 levels with
changes) with a BackButton and a "home->Level1" button on the right.
All works just fine until in the editable TextView I add a second NavigationBar
below the existing NavBar. This second NavBar has two buttons
as well. They are Save/Cancel.
When I click these Save and Cancel buttons the correct action
methods are reached. All is perfect with one exception, The text
which is typed does not appear in the TextView until either
the Save or the Cancel button is touched. The relevant Button setup and
action methods in my TabViewController.m are below. I need to persist this
data.
I thought that getting a Notification from the TextView and the action handleTextChange would do the trick, but no luck. I am stuck.
.........
- (void)loadView {
self.myTextView = [[UITextView alloc] init];
self.myTextView.delegate = self;
self.view = self.myTextView;
//UITextViewTextDidChangeNotification
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(handleTextChange:)
name:UITextViewTextDidChangeNotification
object:nil];
NSLog(#"Registered DG_HandleChangeTextNotification with notification center.");
}
- (void)handleTextChange:(NSNotification * )note
{
[self.myTextView setNeedsDisplay] ;
NSLog(#"...Handled Text Change.");
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
// provide my own Done/Save button to dismiss the keyboard
saveNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
saveNavigationBar.barStyle = UIBarStyleBlackOpaque;
UINavigationItem *doneItem = [[UINavigationItem alloc] init];
doneItem.title = #"My Notes";
UIBarButtonItem *doneItemButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self action:#selector(saveAction:)];
UIBarButtonItem *cancelItemButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
action:#selector(cancelAction:)];
[doneItem setRightBarButtonItem:doneItemButton animated:NO];
[doneItem setLeftBarButtonItem:cancelItemButton animated:NO];
[saveNavigationBar pushNavigationItem:doneItem animated:NO];
[self.view addSubview:saveNavigationBar];
[doneItem release];
[cancelItemButton release];
[doneItemButton release];
}
- (void)saveAction:(id)sender
{
// finish typing text/dismiss the keyboard by removing it as the first responder
self.text = self.myTextView.text;
[self.saveNavigationBar removeFromSuperview];
[self.myTextView resignFirstResponder];
}
- (void)cancelAction:(id)sender
{
[self.saveNavigationBar removeFromSuperview];
[self.myTextView resignFirstResponder];
}
The Second NavBar was hiding the area of the UITextEdit
such that I had to type about four lines before I saw the text. I believe
I need to lower the height of the UITextEdit by 44 pixels.