3D Touch Peek and Pop from UITableViewCell how to hand over data to other UIViewController?
Asked Answered
A

3

10

my app stores different attributes in Core Data objects. They are all shown in a UITableView, if you click a cell, a DetailView is shown. the usual stuff like in the Master-Detail-XCode-Template.

Now I want to implement 3D Touch with peek and pop. Like in the Mail app, 3D touch a cell, get preview, press deeper, pop in the detail.

I got this working so far, but I can t figure out how to pass the corresponding data in

- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location

and

- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit

to the other DetailViewController.

If you just click the cell (no 3D touch) I hand over the data in

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
    [[segue destinationViewController] setDetailItem:object];

I am using a

id detailItem

in every ViewController and I set the corresponding object to it.

So I try to get something similar to work, so in my DetailViewController my "detailItem" needs the corresponding Core Data object from the selected (3D touched) cell.

Thanks for help !

Ankylose answered 7/10, 2015 at 21:22 Comment(0)
B
6

Get the destination View controller from the storyboard using its storyboard ID and pass the objects that you are doing in prepareForSegue method.

Below is the code that I use to pass the data. Its in Swift, it should be similar in objective C. Let me know if you want Objective C version.

func previewingContext(previewingContext: UIViewControllerPreviewing,viewControllerForLocation location: CGPoint) -> UIViewController? method:

    // Obtain the index path and the cell that was pressed.
    guard let indexPath = tableView.indexPathForRowAtPoint(location),
              cell = tableView.cellForRowAtIndexPath(indexPath) else { return nil }

    // Create a destination view controller and set its properties.
    guard let destinationViewController = storyboard?.instantiateViewControllerWithIdentifier("DestinationViewController") as? DestinationViewController else { return nil }
    let object = fetchedResultController.objectAtIndexPath(indexPath)
    destinationViewController.detailItem = object

    /*
        Set the height of the preview by setting the preferred content size of the destination view controller. Height: 0.0 to get default height
    */
    destinationViewController.preferredContentSize = CGSize(width: 0.0, height: 0.0)

    previewingContext.sourceRect = cell.frame

    return destinationViewController
}
Belle answered 8/10, 2015 at 23:42 Comment(3)
Thanks, I was really close but messed something up ... ;)Ankylose
@Belle Dir sir you did not mention that you took this piece of code from apple. developer.apple.com/library/content/samplecode/…Sox
guard let indexPath = tableView.indexPathForRowAtPoint(location), cell = tableView.cellForRowAtIndexPath(indexPath) else { return nil } This method is giving the wrong index. Is there any way to get tapped view using 3D touch?Anaya
T
8

If you are using storyboard segues from the cell to the new view controller, the sender is the table view cell.

So you could implement prepareForSegue: as such:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([sender isKindOfClass:[UITableViewCell class]]) {

        UITableViewCell *cell = sender;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

        id viewController = segue.destinationViewController;

        // Get your data object
        // Pass it to the new view controller
    }
}
Tauten answered 6/11, 2015 at 22:28 Comment(0)
B
6

Get the destination View controller from the storyboard using its storyboard ID and pass the objects that you are doing in prepareForSegue method.

Below is the code that I use to pass the data. Its in Swift, it should be similar in objective C. Let me know if you want Objective C version.

func previewingContext(previewingContext: UIViewControllerPreviewing,viewControllerForLocation location: CGPoint) -> UIViewController? method:

    // Obtain the index path and the cell that was pressed.
    guard let indexPath = tableView.indexPathForRowAtPoint(location),
              cell = tableView.cellForRowAtIndexPath(indexPath) else { return nil }

    // Create a destination view controller and set its properties.
    guard let destinationViewController = storyboard?.instantiateViewControllerWithIdentifier("DestinationViewController") as? DestinationViewController else { return nil }
    let object = fetchedResultController.objectAtIndexPath(indexPath)
    destinationViewController.detailItem = object

    /*
        Set the height of the preview by setting the preferred content size of the destination view controller. Height: 0.0 to get default height
    */
    destinationViewController.preferredContentSize = CGSize(width: 0.0, height: 0.0)

    previewingContext.sourceRect = cell.frame

    return destinationViewController
}
Belle answered 8/10, 2015 at 23:42 Comment(3)
Thanks, I was really close but messed something up ... ;)Ankylose
@Belle Dir sir you did not mention that you took this piece of code from apple. developer.apple.com/library/content/samplecode/…Sox
guard let indexPath = tableView.indexPathForRowAtPoint(location), cell = tableView.cellForRowAtIndexPath(indexPath) else { return nil } This method is giving the wrong index. Is there any way to get tapped view using 3D touch?Anaya
A
2

Base on Dheeraj's reply, adjust some code to rectify the wrong touch location of tableview cell. Assume we need pass the value named type to destination controller.

- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location{
// check if we're not already displaying a preview controller
if ([self.presentedViewController isKindOfClass:[DetailViewController class]]) {
    return nil;
}

CGPoint cellPostion = [self.tableview convertPoint:location fromView:self.view];
NSIndexPath *path = [self.tableview indexPathForRowAtPoint:cellPostion];

if (path) {
    UITableViewCell *cell = [self.tableview cellForRowAtIndexPath:path];
    type = [[self.data objectAtIndex:path.row] integerValue];
    // shallow press: return the preview controller here (peek)
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    DetailViewController *previewController = [storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"];
    previewController.type = type;
    previewingContext.sourceRect = [self.view convertRect:cell.frame fromView:self.tableview];
    return previewController;
}
return nil;

}

Antisemite answered 10/10, 2015 at 14:28 Comment(2)
Just call [self registerForPreviewingWithDelegate:self sourceView:self.tableView] somewhere like viewDidLoad to make [self.tableview convertPoint:location fromView:self.view] call not necessary. Conversion will be done for you by UIKit.Peruse
There is a problem while using [self registerForPreviewingWithDelegate:self sourceView:self.tableView]. That is the snapshot of the 3d touch animation is not including contentView.transform state. Let's say you set contentView.transform = TransformHelper.reverse() to each cell, then you'll end up with upside down cell s while the 3d touch animation is running.Hibben

© 2022 - 2024 — McMap. All rights reserved.