I have a UITableView embedded in a UIPopoverController, as shown below.
When I select a cell, the textField in the cell becomes firstResponder. But instead of keeping the tableview scrolled to the top, all content goes away (even though there are no more than 4 cells). It is impossible to scroll to the top will this happens. After dismissing the keyboard everything is normal again.
The following code does not resolve the problem:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CRShoppingListItemCell *cell = (CRShoppingListItemCell *) [tableView cellForRowAtIndexPath:indexPath];
cell.itemTextField.enabled = YES;
cell.itemTextField.delegate = self;
[cell.itemTextField becomeFirstResponder];
[tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionNone animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
My guess is you aren't using the UITableViewController. Inside that controller's viewWillAppear it checks for isInViewControllerThatHandlesKeyboardAvoidance (private) and one of those controllers is the popover controller. So if it is that then the keyboard avoiding behaviour you would usually want when the table is full screen is turned off.
Related
I have dynamic tableview for which I have 6 cells.
Problem statement:
Now, I want to show a popover which should come just right to the selected cell and with arrow pointing left towards the cell .
What I did :
1) created the PopUpViewController.m/.h .
2) created a "Present as popover" segue from the cell to this popUpViewController.
3) currently anchor point in storyboard is set to tableview so the popover shows from the top left corner.
After some reading,
1) I created a XTableViewCell.m/.h class for the cell.
2) created a small button towards right end in the cell and put an outlet of it in XTableViewCell.h file to use this button as an anchor.
MY question is , I have done all this in storyboard.
Consider my tableViewController class as YTableViewController.h/.m
1) Where and how should I use the anchor button to anchor my popover to my requirement ?
2) By default, in story board the anchor is set to the cell name . Will it be overwritten to my button ?
3) Where should I configure the UIPopoverPresentationController params ?
4) How can show the popup as "popup" in iPhone also and not as full screen view controller?
Please help.
First, you should create a popover segue from your view controller with your table view in it. You can do this by control dragging from the yellow view controller icon in the document outline to the view controller you want to popover. Give it a segue identifier, by clicking on the segue and opening the attributes inspector and adding it to the segue identifier field. Something like "Popover" will work for now.
Next, you should drag from the anchor view circle below the segue identifier field to your view controller's view (we'll adjust this later in code).
You should add a button to your UITableViewCell subclass. Then in your cellForRowAtIndexPath: you can add a target for the button like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = [menuItems objectAtIndex:indexPath.row]; // I'm not sure what's going on here but hopefully you do
RegisterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[cell.PopoverAnchorButton addTarget:self action:#selector(presentPopover:) forControlEvents:UIControlEventTouchUpInside];
// Configure the cell...
return cell;
}
Add the presentPopover: method to your view controller:
- (void) presentPopover:(UIButton *)sender
{
[self performSegueWithIdentifier:#"Popover" sender:sender];
}
Now, you can change the source view in your view controller's prepareForSegue:
You can get a reference to the UIPopoverPresentationController and check if the source view is an instance of your subclass of UITableViewCell. If so, adjust the source view to its button.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Popover"] && segue.destinationViewController.popoverPresentationController) {
UIPopoverPresentationController *popController = segue.destinationViewController.popoverPresentationController;
popController.sourceView = sender;
popController.delegate = self;
// if you need to pass data you can access the index path for the cell the button was pressed by saying the following
CGPoint location = [self.tableView convertPoint:sender.bounds.origin fromView:sender];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
// do something with the indexPath
}
}
If you want the view controller to always be displayed as a popover even on implement the UIPopoverPresentationControllerDelegate method:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller{
return UIModalPresentationStyleNone;
}
At this point, you'll likely have a warning. This can by silenced by telling the complier that you conform to the UIPopoverPresentationControllerDelegate protocol. For example:
#interface MyTableViewController () <UITableViewDataSource, UITableViewDelegate,UIPopoverPresentationControllerDelegate>
I have two view controllers, the main linked to a navigation controller. I created a segue by linking the main controller to the second on the storybaord. I've called the Identifier "Associate" and made it a push segue.
I create table view cells with a button attached to the accessory view programatically (this is deliberate). The button calls performSegueWithIdentifier, but it doesn't show the second view controller. Aside my iffy technical language (only been IOS for a week, sorry) any idea what I'm doing wrong?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
//...
[myButton addTarget:self action:#selector(buttonizeButtonTap:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = myButton;
return cell;
}
-(void)buttonizeButtonTap:(id)sender{
[self performSegueWithIdentifier:#"Associate" sender:sender];
}
OK, realised what I did wrong. I had put an empty performSegueWithIdentifier method override. The danger of running before I can walk. Thanks for all your help.
I have just started working with tableViews, and I have 5 cells in a tableview in a viewController embedded in a navigationController. When a cell is pressed another view is pushed in. My problem is that the cell I press is selected but the selection doesn't go away. I have tried with this code:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
NewViewController *newViewController = [[NewViewController alloc] init];
newViewController.theTitle = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
[self.navigationController pushViewController: newViewController animated:YES];
}
The tableView is initialized in the viewDidLoad method. Still when I click a cell the new viewController is pushed in but the cell stays selected. What might be the issue here?
You've put your code in the didDeselectRowAtIndexPath - put it in the didSelectRowAtIndexPath. This is an easy mistake to make since didDeselect comes up in code completion before didSelect.
Summary :
You have tableview that is in a ViewController that is in a NavigationController
Use touch a cell
A new ViewController is push on the NavigationController Stack
User hit back and goes back to the screen where you have a tableView
That is what I understand from your question.
At this moment the cell in your tableView should still be selected in order for the user to have a reminder of the last action he as done, but you also want it to get unselected animated at the point ( the mail application is a good example of this behaviour).
So the best place to deselect the cell in your tableView is in - (void)viewDidAppear:(BOOL)animated method of the UIViewController that have the tableview inside it's view. By doing so you will let the user a chance to see the selection before it gently fade away like in mail.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
You can pass nil as argument of deselectRowAtIndexPath, tableView handles it gracefully.
Did you also implement tableView:didSelectRowAtIndexPath:? This method is called every time you tap a cell. So you should put your code there.
The method you are using, tableView:didDeselectRowAtIndexPath: is called whenever a cell is selected and you are tapping a different cell.
I think your problem is that you use wrong method. Change didDeselectRowAtIndexPath to didSelectRowAtIndexPath.
I have a viewController that has a container view. In the container view I have a tableView that contains static cells. Each cell has a disclosure indicator. This was all created in IB. The parent viewController is embedded in a navigationController.
Each cell pushes a new view controller which loads a mapView. Each map parses and loads a .kml file. The .kml files are huge and take up to a minute (or more) to load.
I placed an activityIndicator in the accessory view of each cell using the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIActivityIndicatorView *activityView =
[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityView startAnimating];
[cell setAccessoryView:activityView];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];}
This appears to work as expected.
After viewing the map I touch the "back" button provided by the navigationController and pop the map off the stack. My embedded tableView is visible again, with the activity indicator still spinning. I can't get it to stop.
My best attempt was in the implementation file of my tableView:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[self tableView] reloadData];}
But that didn't work. Any suggestions?
Calling reloadData in the table view controller's viewWillAppear would work as long as in the cellForRowAtIndexPath method, you're setting the state for UIActivityIndicatorView by calling it's stopAnimating method (or simply remove it from the view) for any cell that shouldn't be spinning.
You'll need to reference the activity indicator via the accesstoryView property.
In your data, you could store a property that indicates whether the indicator should still be spinning for that map and set it appropriately.
Another method would be to stop the activity indicator in prepareForSegue, just prior to showing the map view.
I have a UITabBarController template based app where the first tab is a UITableViewController with custom buttons in the cells. I need one button in one cell to call a specific tab in the parent UITabBarController. Im using this code in the didSelectRowAtIndexPath:
case 5:
NSLog(#"Search");
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Get UITabBar instance and send it message
UITabBarController *tabBar = (UITabBarController*)[self parentViewController];
[tabBar setSelectedIndex:1];
break;
When I tap on this row the app crashes without any log in the console. Im calling this in that UITableViewController which is the first tab in the UITabBarController.
PS I also want to avoid the blue selection on this cell that occurs when the user taps. So I added this code:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
switch (indexPath.row) {
case 1:
return nil;
break;
}
}
But it still selects blue when I tap on it. Could they be related issues?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
UITabBarController *tabController = (UITabBarController *) UIApplication.sharedApplication.keyWindow.rootViewController;
[tabController setSelectedIndex:1];
}
the first message will deselect the row, avoiding the blue selection.
As your app is tab-based, the root controller of the key window is always an instance of UITabBarController.