I've implemented a long press gesture recognizer on a table view cell that shows the UIMenuController and when menu shows, the corresponding table view cell is getting selected which is my requirement.But the problem is when I touches out side,UIMenuController is getting dismissed but the cell is still in selected state.How to deselect the cell when pressing outside
I hope that, you are using the UIPopOverController to show the Menu .
Use the Delegate of popoverControllerDidDismissPopover event to get your solution
- (void) popoverControllerDidDismissPopover:(UIPopoverController *) popoverController {
[myTable deselectRowAtIndexPath:[myTable indexPathForSelectedRow] animated:YES];
}
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 got a search bar and a table view setup in my project. Now I want a nice way of dismissing the keyboard just when the user touches the screen anywhere outside of the search bar.
//Search bar tap recognizer
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[tap setCancelsTouchesInView:NO];
[self.tableView addGestureRecognizer:tap];
This works so far - if I leave the following line out:
[tap setCancelsTouchesInView:NO];
The tap recognizer kind of overlaps the didSelectRowAtIndexPath method so if I wanted to select a row, I had to sort of slide across the cell to trigger the didSelectRowAtIndexPath method.
Anyways with that line if you tap outside of the search bar, the keyboard disappears but the didSelectRowAtIndexPath is also triggered - since most of the time the user would just tap in the middle of the screen - right at a cell of the table view.
How can I keep the table view method didSelectRowAtIndexPath from being called the first time if the search bar is still "active"? Because I think it's pretty annoying if you just want to dismiss the keyboard and you then the detail view of the tapped cell shows up.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if([self.view isFirstResponder])
{
[self.view endEditing:YES];
cell.userInteractionEnabled = NO;
} else {
cell.userInteractionEnabled = YES;
//if you have to do some actions when cell is selected
}
}
In order to dismiss the keyboard just when the user touches the screen anywhere outside of the search bar, you can call "dismiss keyboard" method inside table view didSelectRowAtIndexPath delegate. So it will work as needed.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissKeyboard];
// you can write detail page navigation code here.
}
When I use
tableView:didSelectRowAtIndexPath / popViewControllerAnimated
it does not work. I push the view controller by another view but when I select a row, it highlights in gray instead of immediately popping to the original view controller. But when I tap another row, it selects the first row I tapped and then goes back to the original view controller.
Here is the code:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
NSArray *allTypes = [[ItemStore sharedStore] allTypes];
NSManagedObject *raum = allTypes[indexPath.row];
self.an.leben = raum;
[self.navigationController popViewControllerAnimated:YES];
}
Any ideas?
Replacde didDeselectRowAtIndexPath with didSelectRowAtIndexPath.
The delegate method you have written is didDeselectRowAtIndexPath instead of didSelectRowAtIndexPath.
According to apple, tableView:didDeselectRowAtIndexPath:
Tells the delegate that the specified row is now deselected.
and
tableView:didSelectRowAtIndexPath:
Tells the delegate that the specified row is now selected.
So, what is happening is, when you click on a row, it becomes selected and turns gray and then when you click on the same or any other row, the previous one gets deselected because only one row is selected at once and hence calls this method to open the next view controller with the previous tapped row.
Change tableView:didDeselectRowAtIndexPath into tableView:didSelectRowAtIndexPath.
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.