I have a tableView that has several table cells with TextFields as subviews
self.cellFirstName = [[UITableViewCell alloc] initWithFrame:cellRectangle];
self.tfFirstName = [[UITextField alloc] initWithFrame:Field1Frame];
self.tfFirstName.tag = 1;
self.tfFirstName.delegate = self;
self.tfFirstName.placeholder = #"First Name";
[self.cellFirstName addSubview:self.tfFirstName];
...
if(indexPath.section == 0) {
cell = self.cellFirstName;
}
the keyboard does not pop up when you touch the textField on a real iPad or click on the the TextField on a iPad simulator.Works find on real and sim iPhone.
Somehow I can't do anything to make the keyboard pop up.
If I set one of the textFields as 1st responder then a keyboard shows up,but when I dismiss the keyboard and hit any of the textFields - nothing - no keyboard.
clicking or touching the textFields just turns them blue.
I even copied the iPhone storyboard to iPad
and
changed targetRuntime to "iOS.CocoaTouch.iPad"
still same results.
here is the hack I'm using to get this to work:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section == 0) {
[self.tfFirstName becomeFirstResponder];
}
if(indexPath.section == 1) {
[self.tfLastName becomeFirstResponder];
} ...
I would rather understand what is keeping the keyboard from popping up.
If you have some special code for iPad , i'm thinking maybe you have set the tfFirstName.userInteraction = NO; and/or tfFirstName.enabled = NO; or one of the delegate methods to return NO when the device is iPad. Check those please.
Related
In an iOS apps I have a table view that has 2 rows with textfield embedded inside.
Textfield2 is a textfield with pickerview input that I set with something like this:
textField2.inputView = pickerView;
So the thing is , the textField 2 icon on the right is only an image embedded in the textfield2.rightview that caused the image to not trigger the pickerView input when tapped.
Did select table view method also wasn't triggered because I set the textfield to fully occupy the cell. Thus, after some searching I find that disabling the textField2 user interaction enabling the didSelect to be triggered.
textField2.userInteractionEnabled = false;
However, now I'm at lost on to how to trigger the input to textField2 pickerView via the didselect tableview method. I tried this line of code but that doesn't work.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2 becomeFirstResponder];
}
}
I tried to search how to trigger input manually to textField and didn't find any clue.
Thanks before ! :)
After some debugging with a clear mind, I find that
textField2.userInteractionEnabled = false;
caused the textfield not able be the responder.
So a little workaround with this flag is enable it first in order to edit the text field and disable it again after we finished editing. Something like this :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2.userInteractionEnabled = true;
[textField2 becomeFirstResponder];
}
}
- (void)donePicker {
// to enable the did select row again
[textField2.userInteractionEnabled = true;
}
This problem happens with SDK 8.1, when running under iOS 8.1, but not when running under iOS 7. It is for iPad only. The problem appears both with simulator and on a hardware device.
The code below demonstrates a view controller that contains a UITableView with 1 row, and below that, a UIButton. Tapping on the button or on the row will cause a popover to appear. This works just fine when tapping the button, but when tapping the row of the tableview, the popover appears with some delay. In my testing, first time I tap the row the popover usually appears with little or no delay, but second time I tap the row, it can take many seconds before the popover appears, and often it does not appear until I tap somewhere else on the view. However, the delay can happen even at the first tap on the row (especially when tested on hardware).
The code I show has been boiled down as much as possible, while retaining the problem. It seems to me, that the UITableView is somehow critical to cause this delay to happen.
I do know that some of the UIPopoverController code is deprecated under iOS 8. I have tried to use UIPopoverPresentationController for iOS 8, and the result is the same: A sometimes very long delay before the popover appears. I am not yet very familiar with this new approach, so I may well be making mistakes, but in any case the iOS 8 code can be tested by setting the USE_TRADITIONAL_METHOD macro to 0 instead of 1.
Any suggestions on how to fix or bypass this (while still using a tableview) will be greatly appreciated.
#import "MyViewController.h"
#interface MyViewController ()
#property (nonatomic) UIPopoverController* myPopoverController;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// setup table view
UITableView* tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 500, 500) style:UITableViewStyleGrouped];
[self.view addSubview:tableView];
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tableView.dataSource = self;
tableView.delegate = self;
// setup button
UIButton* button = [UIButton buttonWithType:UIButtonTypeSystem];
[self.view addSubview:button];
button.frame = CGRectMake(20, 550, 100, 20);
[button setTitle:#"Show popover" forState:UIControlStateNormal];
[button addTarget:self action:#selector(showPopover:) forControlEvents:UIControlEventTouchUpInside];
}
- (IBAction)showPopover:(id)sender
{
UIView* senderView = (UIView*)sender;
UIViewController* contentViewController = [[UIViewController alloc] init];
contentViewController.view.backgroundColor = [UIColor purpleColor];
#define USE_TRADITIONAL_METHOD 1
#if USE_TRADITIONAL_METHOD
self.myPopoverController = [[UIPopoverController alloc] initWithContentViewController:contentViewController];
[self.myPopoverController presentPopoverFromRect:senderView.frame inView:senderView.superview permittedArrowDirections:UIPopoverArrowDirectionLeft animated:NO];
#else
contentViewController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:contentViewController animated:NO completion:^{
NSLog(#"Present completion"); // As expected, this is executed once the popover is actually displayed (which can take a while)
}];
// do configuration *after* call to present, as explained in Apple documentation:
UIPopoverPresentationController* popoverController = contentViewController.popoverPresentationController;
popoverController.sourceRect = senderView.frame;
popoverController.sourceView = senderView;
popoverController.permittedArrowDirections = UIPopoverArrowDirectionLeft;
#endif
NSLog(#"Popover is visible: %d", self.myPopoverController.isPopoverVisible); // This shows "1" (visible) for USE_TRADITIONAL_METHOD, under both iOS 7 and iOS 8
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.textLabel.text = #"Show popover";
return cell;
}
#pragma mark - UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self showPopover:[tableView cellForRowAtIndexPath:indexPath]];
}
#end
I found that deselecting the row before attempting to show the popover seems to fix the problem. This may be a useful work-around, but I'm still looking for a better answer, since this may not be robust.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO]; // adding this line appears to fix the problem
[self showPopover:[tableView cellForRowAtIndexPath:indexPath]];
}
Note, as Yasir Ali commented, that for this workaround to work, deselect animation must be off. Almost 4 years after the original post, this behavior still affects iOS 12, and the bug report with Apple is still open - sigh.
I had the same issue, and deselecting the cell prior to displaying the popover did nothing to resolve my issue. What did work for me was dispatching the popover code to the main queue with a minuscule delay. This produces consistent display of the popover AND allows me to keep the cell SELECTED, which is key to my UI:
Expected UI
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch actions[indexPath.row] {
case .rename:
....
case .duplicate:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01, execute: {
let copyController = UIStoryboard.init(name: "Actions", bundle: nil).instantiateViewController(withIdentifier: "copyToNavController")
copyController.modalPresentationStyle = .popover
let cell = tableView.cellForRow(at: indexPath)
copyController.popoverPresentationController?.sourceView = cell
if let frame = cell?.frame {
copyController.popoverPresentationController?.sourceRect = frame
}
copyController.popoverPresentationController?.permittedArrowDirections = .left
self.popoverPresenter = copyController.popoverPresentationController
self.present(copyController, animated: true, completion: nil)
})
default:
break
}
}
Many thanks for that trick.
I have a TableView that displays a popover when I click on a line. My popover was displaying only after a delay, or even was requiring a double click on the line to finally show up. By adding the indicated line ([tableView deselectRowAtIndexPath: indexPath animated: NO]) the popover is displayed immediately without having to double click anymore.
I'm new to ios.Please guide me if you found something wrong. Here is my scenario.
UITableViewCell is showing a label and a button. Button should appears only when the cell is selected. As sometime they both get overlaps if label text is large. So decided to add button as Accessory view. Adding button to UITableViewCell's Accessory View is working in iPhone. Button appears in iPad landscape mode only.Its not showing button in iPad portrait mode. Did I miss something. Is there anyone found something similar.
- (void)tableView:(UITableView *)tview didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tview cellForRowAtIndexPath:indexPath];
cell.accessoryView = joinButton;
}
- (void)tableView:(UITableView *)tView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tView cellForRowAtIndexPath:indexPath];
cell.accessoryView = nil;
}
- (void)viewDidLoad{
NSString *joinLabel = NSLocalizedString(#"Join", #"");
self.joinButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[joinButton setTitle:joinLabel forState:UIControlStateNormal];
/* set join button frame **/
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.isSelected) {
cell.accessoryView = joinButton; // No reason to create a new one every time, right?
}
else {
cell.accessoryView = nil;
}
}
It just shows join button in portrait mode only when its already showing in landscape mode and then you change rotation from landscape to portrait. Again clicking on some other cell does not show button on that particular selected cell. Ideally it should show button every time you click on cell in both orientation mode.
Thanks
Are you reloading table view on rotation?
You have done coding for (cell.accessoryView = joinButton;)in didSelectRowAtIndexPath instead do coding in cellForRowAtIndexPath of UITableViewDataSource or in a willDisplayCell of UITableViewDelegate.
I've got a UIPopoverController created programmatically which pops up with the content from a UIViewController from a .xib. The UIViewController contains a (grouped) UITableView and a UITableViewCell "prototype".
When The popover pops up, the cell prototype is duplicated for all cells needed. The number of cells exceeds the size of the popover, so I can scroll through all cells.
When the popover pops up, everything looks nice, the cell labels are all left aligned. As soon as I touch the tableview to scroll, all cell labels suddenly align to center. When I scroll the cells outside and back in, the are left aligned again. After I scrolled all cells outside for once, they keep left aligned for the rest of their lifetime. I have no idea what is causing this... there is nothing in my code that alters the alignment of the cells. Here's some code:
UIViewController *editPopoverView = [[[ComponentViewEmptyEditPopover alloc] initWithNibName:#"ComponentViewEmptyEditPopover" bundle:nil] autorelease];
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:editPopoverView];
aPopover.delegate = self;
[aPopover presentPopoverFromRect:sender.frame inView:self permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
From the popover viewcontroller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *theCell = nil;
switch (indexPath.section)
{
case 0:
theCell = [tableView dequeueReusableCellWithIdentifier:#"typeCell"];
if (theCell == nil)
{
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.typeCell];
theCell = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
switch (indexPath.row)
{
case 0:
[theCell.textLabel setText:#"Empty"];
break;
//
}
break;
}
return theCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1)
return 420;
return 44;
}
Any ideas why this is happening? I guess this is somehow related to cell reuse.
Update: Like I already guessed, it has to to with the reusing. When I do
theCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"theCell"];
everything works fine. However, I want to be able to change the design of the cell through interface builder...
Update 2: If I comment out the dequeueReusableCellWithIdentifier line, all cells will go back to center alignment after they scroll in.
I have a UITextField with a tag inside a prototype cell. The UITextField is set to become first responder when the UITableView is being built and a UISwitch in the cell above is turned on.
This works if the app starts from scratch or if it was closed and restarted. Once it's loaded the [tableView reloadData] doesn't trigger the becomeFirstResponder anymore.
If the UITextField becomes first responder by touching the textfield later on, I can trigger the becomeFirstResponder event with buttons, with pop ups,...
But not with my switch any more.
Any pointers as to what I can try?
Currently, I use the didSelectRowAtIndexPath method to trigger a pop up. A nice side effect is, that when I pull up the number keypad, I can provide an ok and cancel button within the pop up instead of having to fiddle with separate buttons on the keypad. But it just seems so obviously to be a workaround.
This is how I call firstresponder when building the UITableView (which works every time the app starts from scratch):
if ([settings doubleForKey:#"limitDouble"]==0 && [settings boolForKey:#"limitBool"]==YES) {
[dailyLimitEntry becomeFirstResponder];
}
dailyLimitEntry is a UITextField which is strong so it stays around.
Just for fun I added a button and connected it to my code like this:
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
This works, too. When I use it with the switch, it's only called once the app is freshly loaded in the memory. Otherwise, my UITextField doesn't respond to the switch.
After the first comments, I found a method to check whether or not the UITableView has finished reloading
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if([indexPath row] == ((NSIndexPath*)[[settingsTableView indexPathsForVisibleRows] lastObject]).row){
//end of loading
//for example [activityIndicator stopAnimating];
NSLog(#"finished reload");
NSLog(#"%#",dailyLimitEntry);
if ([settings boolForKey:#"limitBool"]==YES) {
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
}
}
}
Fun thing though is, become first responder is only triggered the first time the switch is used after the app loaded. Initially, the switch is off. So the cell containing the UITextField is not drawn yet. Once I switch to ON, the UITextField gets drawn in the second cell and becomes first responder. If I switch OFF and ON again, I still get my log "finished reload", but the UITextField doesn't become first responder. It's driving me nuts....
Must be something about the life cycle of the app.
Rather than checking the indexPath, check the cell's class.
Here's what I do to bring up the keyboard for a title cell that's blank (when I create a new item):
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[FDSSampleTitleCell class]]) {
FDSSampleTitleCell *titleCell = (FDSSampleTitleCell *)cell;
if (titleCell.titleField.text.length == 0) {
[titleCell.titleField becomeFirstResponder];
}
}
}