【iOS特性】3D Touch 预览和弹出

274 阅读3分钟

预览和弹出(Peek and Pop)

Peek and Pop 是指用户在手机屏幕上用力按压想要预览的选项,弹出一个可以预览二级页面的预览窗口,可以设置一些快捷的操作选项,以类似 sheetAlertView 的方式呈现出来。最后附上完整代码。

图片

代码实现

1.注册视图代理

注意:对于不支持 3D Touch 的设备不会报错,但无法触发 Peek And Pop

注册 Peek And Pop 代理前需要判断设备是否支持 3D Touch

typedef NS_ENUM(NSInteger, UIForceTouchCapability) {
    UIForceTouchCapabilityUnknown = 0, // 未知错误
    UIForceTouchCapabilityUnavailable = 1, // 不支持
    UIForceTouchCapabilityAvailable = 2 // 支持
};
- (BOOL)check3DTouch {
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        return YES;
    }
    return NO;
}

对支持 3D Touch 的设备再进行注册

// iOS 9及以上且支持3D Touch
if (@available(iOS 9.0, *)) {
    if ([self check3DTouch]) {
        // 注册代理,传入响应3D Touch的视图
        [self registerForPreviewingWithDelegate:self sourceView:self.label];
    }
}

registerForPreviewingWithDelegate 参数:

  • delegate:  Peek And Pop 代理对象

  • sourceView:触发 Peek And Pop 的视图控件

2.实现预览协议

Peek And Pop 功能需要实现 UIViewControllerPreviewingDelegate 的两个代理方法

UIKIT_EXTERN API_AVAILABLE(ios(9.0)) NS_SWIFT_UI_ACTOR
@protocol UIViewControllerPreviewingDelegate <NSObject>

// If you return nil, a preview presentation will not be performed
- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location API_DEPRECATED("UIViewControllerPreviewing is deprecated. Please use UIContextMenuInteraction.", ios(9.0, 13.0)) API_UNAVAILABLE(visionos);
- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit API_DEPRECATED("UIViewControllerPreviewing is deprecated. Please use UIContextMenuInteraction.", ios(9.0, 13.0)) API_UNAVAILABLE(visionos);

@end
#pragma mark - peek and pop Delegate
// pop 加重按压力度弹起的界面
- (void)previewingContext:(nonnull id<UIViewControllerPreviewing>)previewingContext commitViewController:(nonnull UIViewController *)viewControllerToCommit {
    // 将配置好的控制器推入导航栈
    [self.navigationController pushViewController:viewControllerToCommit animated:YES];
}

// peek 长按预览界面,其他区域则会变模糊
- (nullable UIViewController *)previewingContext:(nonnull id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
    self.count++;
    // 创建要返回的viewController
    DetailViewController *detailVC = [[DetailViewController alloc] init];
    detailVC.message = [NSString stringWithFormat:@"count: %ld", self.count];
    // 设置预览视图的大小
    detailVC.preferredContentSize = CGSizeMake(300, 500); // 根据需要调整大小
    // 启用其他UI元素模糊,该区域内不被虚化,通常为触摸控件的位置, 不设置,将使用系统提供的合适区域。
    previewingContext.sourceRect = self.label.frame;
    return detailVC;
}
  • 唤起Peek:长按【Peek & Pop】控件,此时就会触发 - (nullable UIViewController*)previewingContext:viewControllerForLocation:代理方法,返回detailVC预览视图对象,并根据设置的预览视图大小进行展示

  • 唤起Pop:在唤起 Peek 的前提下继续加大按压力度就会触发- (void)previewingContext: commitViewController:代理方法,展示完整的预览页面

图片

预览视图的大小可根据 preferredContentSize 调节,

图片

3.预览菜单

在提供预览的控制器中提供 previewActionItems 预览菜单数据即可

#pragma mark - previewActionItems Delegate
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
    UIPreviewAction *noReadAction = [UIPreviewAction actionWithTitle:@"标为未读" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"标为未读");
    }];
    
    UIPreviewAction *stickAction = [UIPreviewAction actionWithTitle:@"置顶" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"置顶");
    }];

    UIPreviewAction *deleteAction = [UIPreviewAction actionWithTitle:@"删除" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"删除");
    }];
    
    return @[noReadAction, stickAction, deleteAction];
}

图片

预览菜单也支持 group 概念,点击一个菜单操作会展开其子菜单

- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
    UIPreviewAction *noReadAction = [UIPreviewAction actionWithTitle:@"标为未读" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"标为未读");
    }];
    
    UIPreviewAction *stickAction = [UIPreviewAction actionWithTitle:@"置顶" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"置顶");
    }];

    UIPreviewAction *deleteAction = [UIPreviewAction actionWithTitle:@"删除" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
        NSLog(@"删除");
    }];
    
    UIPreviewActionGroup *group = [UIPreviewActionGroup actionGroupWithTitle:@"group" style:UIPreviewActionStyleDefault actions:@[noReadAction,stickAction]];
        
    return @[group, deleteAction];
}

点击【Group】会再次弹起子菜单

图片

项目链接

代码量有点多,我放到了github上,需要的自取

友情提示

见原文:【iOS特性】3D Touch 预览和弹出)

本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。