Xhacker’s Base

3D Touch Peek and Pop 二三事

3D Touch 有一个 Peek and Pop 功能,简单的说就是用力按可以预览即将载入的 view controller,再按下去将其变为全屏。前几天给 Expense 实现了,在这里记录一下。

先来看一下 Expense 的效果:

典型的 Peek and Pop 在 peek 时载入 view controller,在 pop 时将 view controller push 到 navigation stack 中。这种 Peek and Pop 在两个阶段共享同一个 view controller,实现起来比较简单,可以参见 Little Bites of Cocoa 上的这篇文章

而 Expense 希望在 pop 时将 view controller 作为 modal 弹出,这样就不能使用 showViewController:sender: 了(这个方法只能把 view controller 推入 navigation stack)。也就是说,要为 peek 和 pop 使用不同的 view controller。带来的额外好处是可以很简单地为 preview 使用完全不同的 UI。

Expense 在 preview 阶段就用了完全不同的 UI:

Expense screenshot for peek Expense screenshot for pop

实现起来也不复杂,首先将 table view 注册为支持 3D Touch:

[self registerForPreviewingWithDelegate:self sourceView:self.tableView];

然后实现 UIViewControllerPreviewingDelegate 的两个方法就可以了:

#pragma mark - UIViewControllerPreviewingDelegate

- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location
{
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    if (!cell) {
        return nil;
    }
    // 保存 index path,在 performSegueWithIdentifier:sender: 里会用到
    self.previewingIndexPath = indexPath;
    
    TYKPreviewViewController *previewVC = [[TYKPreviewViewController alloc] initWithNibName:@"TYKPreviewViewController" bundle:nil];
    TYKTaiyaki *taiyaki = [self.fetchedResultsController objectAtIndexPath:indexPath];
    previewVC.taiyaki = taiyaki;
    previewVC.preferredContentSize = CGSizeMake(0, 180);
    previewingContext.sourceRect = cell.frame;
    
    return previewVC;
}

- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{
    // 在按下去后,用 performSegueWithIdentifier:sender: 弹出 view controller
    [self performSegueWithIdentifier:@"Edit" sender:self];
}

最后,Expense 真的,真的,快要发布了。:)

comments powered by Disqus