iOS 3D Touch
2016-09-11 13:15
190 查看
3D Touch 介绍
3D Touch的主要应用场景
3D Touch的主要功能模块
1Home Screen Quick Actions
2peek and pop
3Force Properties
Home Screen Quick Action使用与相关api详解
1静态标签
2动态标签
3响应标签的行为
Peek and Pop
Peek and Pop
Preview Action
Force Properties
附模拟器 3D Touch 测试方法
1.A user can now press your Home screen icon to immediately access functionality provided by your app.
2.Within your app, a user can now press views to see previews of additional content and gain accelerated access to features.
第一部分的应用是我们可以通过3D手势,在主屏幕上的应用Icon处,直接进入应用的响应功能模块。这个功能就例如我们上面的日历示例,会在Icon旁边出现一个菜单,点击菜单我们可以进入相应的功能单元。
我个人理解,这个功能,push消息功能加上iOS8推出的扩展today功能,这三个机制使iOS应用变得无比灵活方便,用户可以不需付出寻找的时间成本来快速使用自己需要的功能。
第二部分是对app的一个优化,用户可以通过3D Touch手势在view上来预览一些预加载信息,这样的设计可以使app更加简洁大方,交互性也更强。
(1)提示用户这里有3D Touch的交互,会使交互控件周围模糊:
(2)继续深按,会出现预览视图:
(3)通过视图上的交互控件进行进一步交互:
这个模块的设计可以在网址连接上进行网页的预览交互。
我们先来看静态标签的配置:
首先,在info.plist文件中添加如下键值(我在测试的时候,系统并没有提示,只能手打上去):
先添加了一个UIApplicationShortcutItems的数组,这个数组中添加的元素就是对应的静态标签,在每个标签中我们需要添加一些设置的键值:
必填项(下面两个键值是必须设置的):
选填项(下面这些键值不是必须设置的):
主要的类和 API
系统风格 icon 的枚举:
创建好标签后,需要将其添加如application的hortcutItems数组中
当我们通过标签进入 App 时,就会在 AppDelegate中调用这样一个回调,我们可以获取shortcutItem的信息进行相关逻辑操作。
这里有一点需要注意:我们在 App 的入口函数:
也需要进行一下判断,在launchOptions中有
注意:
1、快捷标签最多可以创建四个,包括静态的和动态的。
2、每个标签的题目和icon最多两行,多出的会用…省略
1、在需要预览的 ViewController 遵循并实现
2、调用
3、在
4、在
注意:在开发 Peek and Pop 的过程中,请记住以下原则:
1、让合适的内容支持 Peek and Pop (不要滥用这项特性);
2、始终返回相同的预览界面 (保持一致性和可预测性);
3、不要在preview代理方法中花太多的时间;
4、为 context 设置正确的 sourceRect
与 Action Sheet 不同的是,系统提供了 UIPreviewActionGroup 类,实现子菜单的功能。
其中,
触摸的类型。
触摸的压力值,其中 1.0 表示一个平均压力值(有系统预定,而不是用户自己设定)。
触控笔的高度(弧度)。
触摸的最大可能的压力值。
当前触摸对象估计的触摸特性。
高度值,仅适用于触控笔触摸类型。当笔平行于平面时,该值为0;当笔垂直于平面时,该值为Pi / 2 。
一个可以让你关联更新后的触摸和原始触摸的索引值,当每个触摸对象的触摸特性发生变化时,该值将会单独增加。
iOS 9.0 之后,
当可用时,返回一个精确的触摸位置。
当可用时,返回一个精确的前一个触摸位置。
返回愁莫比的方位角(弧度)。
返回触控笔的镇的方向上的而单位向量。
获取触摸压力值很简单:
3D Touch的主要应用场景
3D Touch的主要功能模块
1Home Screen Quick Actions
2peek and pop
3Force Properties
Home Screen Quick Action使用与相关api详解
1静态标签
2动态标签
3响应标签的行为
Peek and Pop
Peek and Pop
Preview Action
Force Properties
附模拟器 3D Touch 测试方法
3D Touch 介绍
3D Touch 是 Apple 推出的通过压力感触区分轻按和重按来进行不同的用户交互,为 App 增加额外维度上的交互,它支持的系统版本为 i0S 9.0+,机型为 iPhone 6s。3D Touch的主要应用场景
Apple 文档给出的应用介绍主要有两块:1.A user can now press your Home screen icon to immediately access functionality provided by your app.
2.Within your app, a user can now press views to see previews of additional content and gain accelerated access to features.
第一部分的应用是我们可以通过3D手势,在主屏幕上的应用Icon处,直接进入应用的响应功能模块。这个功能就例如我们上面的日历示例,会在Icon旁边出现一个菜单,点击菜单我们可以进入相应的功能单元。
我个人理解,这个功能,push消息功能加上iOS8推出的扩展today功能,这三个机制使iOS应用变得无比灵活方便,用户可以不需付出寻找的时间成本来快速使用自己需要的功能。
第二部分是对app的一个优化,用户可以通过3D Touch手势在view上来预览一些预加载信息,这样的设计可以使app更加简洁大方,交互性也更强。
3D Touch的主要功能模块
3D Touch 的功能主要分为以下三项:1、Home Screen Quick Actions
通过主屏幕的应用Icon,我们可以用3D Touch呼出一个菜单,进行快速定位应用功能模块相关功能的开发。如上面的日历。2、peek and pop
这个功能是一套全新的用户交互机制,在使用3D Touch时,ViewController中会有如下三个交互阶段:(1)提示用户这里有3D Touch的交互,会使交互控件周围模糊:
(2)继续深按,会出现预览视图:
(3)通过视图上的交互控件进行进一步交互:
这个模块的设计可以在网址连接上进行网页的预览交互。
3、Force Properties
iOS 9 提供了一个新的交互参数:力度。可以检测某一交互的力度值,来做相应的交互处理。例如,我们可以通过力度来控制快进的快慢,音量增加的快慢等。Home Screen Quick Action使用与相关api详解
iOS 9 提供了两种屏幕标签的设置方式,分别是静态标签和动态标签。1、静态标签
静态标签是我们在项目的配置plist文件中配置的标签,在用户安装程序后就可以使用,并且排序会在动态标签的前面。我们先来看静态标签的配置:
首先,在info.plist文件中添加如下键值(我在测试的时候,系统并没有提示,只能手打上去):
先添加了一个UIApplicationShortcutItems的数组,这个数组中添加的元素就是对应的静态标签,在每个标签中我们需要添加一些设置的键值:
必填项(下面两个键值是必须设置的):
UIApplicationShortcutItemType- 这个键值设置一个快捷通道类型的字符串
UIApplicationShortcutItemTitle- 这个键值设置标签的标题
选填项(下面这些键值不是必须设置的):
UIApplicationShortcutItemSubtitle- 设置标签的副标题
UIApplicationShortcutItemIconType- 设置标签 Icon 类型
UIApplicationShortcutItemIconFile- 设置标签的 Icon 文件
UIApplicationShortcutItemUserInfo- 设置信息字典(用于传值)
2、动态标签
动态标签是我们在程序中,通过代码添加的,与之相关的类,主要有三个:UIApplicationShortcutItem- 创建 3D Touch 标签的类
UIMutableApplicationShortcutItem- 创建可变的 3D Touch 标签的类
UIApplicationShortcutIcon- 创建标签中图片 Icon 的类
主要的类和 API
@interface UIApplicationShortcutItem : NSObject <NSCopying, NSMutableCopying> //下面是两个初始化方法 通过设置type,title等属性来创建一个标签,这里的icon是UIApplicationShortcutIcon对象,我们后面再说 - (instancetype)initWithType:(NSString *)type localizedTitle:(NSString *)localizedTitle localizedSubtitle:(nullable NSString *)localizedSubtitle icon:(nullable UIApplicationShortcutIcon *)icon userInfo:(nullable NSDictionary *)userInfo NS_DESIGNATED_INITIALIZER; - (instancetype)initWithType:(NSString *)type localizedTitle:(NSString *)localizedTitle; - //下面这是一些只读的属性,获取相应的属性值 @property (nonatomic, copy, readonly) NSString *type; @property (nonatomic, copy, readonly) NSString *localizedTitle; @property (nullable, nonatomic, copy, readonly) NSString *localizedSubtitle; @property (nullable, nonatomic, copy, readonly) UIApplicationShortcutIcon *icon; @property (nullable, nonatomic, copy, readonly) NSDictionary<NSString *, id <NSSecureCoding>> *userInfo; @end
//这个类继承于 UIApplicationShortcutItem,创建的标签可变 @interface UIMutableApplicationShortcutItem : UIApplicationShortcutItem @property (nonatomic, copy) NSString *type; @property (nonatomic, copy) NSString *localizedTitle;@property (nullable, nonatomic, copy) NSString *localizedSubtitle; @property (nullable, nonatomic, copy) UIApplicationShortcutIcon *icon; @property (nullable, nonatomic, copy) NSDictionary<NSString *, id <NSSecureCoding>> *userInfo; @end
//这个类创建标签中的 icon @interface UIApplicationShortcutIcon : NSObject <NSCopying> // 创建系统风格的icon + (instancetype)iconWithType:(UIApplicationShortcutIconType)type; // 创建自定义的图片icon + (instancetype)iconWithTemplateImageName:(NSString *)templateImageName; @end
系统风格 icon 的枚举:
typedef NS_ENUM(NSInteger, UIApplicationShortcutIconType) { UIApplicationShortcutIconTypeCompose, UIApplicationShortcutIconTypePlay, UIApplicationShortcutIconTypePause, UIApplicationShortcutIconTypeAdd, UIApplicationShortcutIconTypeLocation, UIApplicationShortcutIconTypeSearch, UIApplicationShortcutIconTypeShare, UIApplicationShortcutIconTypeProhibit NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeContact NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeHome NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeMarkLocation NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeFavorite NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeLove NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeCloud NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeInvitation NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeConfirmation NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeMail NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeMessage NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeDate NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeTime NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeCapturePhoto NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeCaptureVideo NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeTask NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeTaskCompleted NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeAlarm NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeBookmark NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeShuffle NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeAudio NS_ENUM_AVAILABLE_IOS(9_1), UIApplicationShortcutIconTypeUpdate NS_ENUM_AVAILABLE_IOS(9_1) } NS_ENUM_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED;
创建好标签后,需要将其添加如application的hortcutItems数组中
- (void)createItemsWithIcons { UIApplicationShortcutIcon *icon1 = [UIApplicationShortcutIcon iconWithTemplateImageName:@"iCon1"]; UIApplicationShortcutIcon *icon2 = [UIApplicationShortcutIcon iconWithTemplateImageName:@"iCon2"]; UIApplicationShortcutIcon *icon3 = [UIApplicationShortcutIcon iconWithTemplateImageName:@"iCon3"]; // create several (dynamic) shortcut items UIMutableApplicationShortcutItem *item1 = [[UIMutableApplicationShortcutItem alloc]initWithType:@"com.test.dynamic" localizedTitle:@"Dynamic Shortcut" localizedSubtitle:@"available after first launch" icon:icon1 userInfo:nil]; UIMutableApplicationShortcutItem *item2 = [[UIMutableApplicationShortcutItem alloc]initWithType:@"com.test.deep1" localizedTitle:@"Deep Link 1" localizedSubtitle:@"Launch Nav Controller" icon:icon2 userInfo:nil]; UIMutableApplicationShortcutItem *item3 = [[UIMutableApplicationShortcutItem alloc]initWithType:@"com.test.deep2" localizedTitle:@"Deep Link 2" localizedSubtitle:@"Launch 2nd Level" icon:icon3 userInfo:nil]; // add all items to an array NSArray *items = @[item1, item2, item3]; // add this array to the potentially existing static UIApplicationShortcutItems NSArray *existingItems = [UIApplication sharedApplication].shortcutItems; NSArray *updatedItems = [existingItems arrayByAddingObjectsFromArray:items]; [UIApplication sharedApplication].shortcutItems = updatedItems; }
3、响应标签的行为
类似推送,当我们点击标签进入应用程序时,也可以进行一些操作,我们可以看到,在applocation中增加了这样一个方法:- ( void )application:( UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:( void (^)( BOOLsucceeded))completionHandler NS_AVAILABLE_IOS ( 9 _0);
当我们通过标签进入 App 时,就会在 AppDelegate中调用这样一个回调,我们可以获取shortcutItem的信息进行相关逻辑操作。
这里有一点需要注意:我们在 App 的入口函数:
- ( BOOL )application:( UIApplication *)application didFinishLaunchingWithOptions:( NSDictionary *)launchOptions;
也需要进行一下判断,在launchOptions中有
UIApplicationLaunchOptionsShortcutItemKey这样一个键,通过它,我们可以区别是否是从标签进入的 App,如果是则处理结束逻辑后,返回
NO,防止处理逻辑被反复回调。
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler { NSLog(@"A shortcut item was pressed. It was %@.", shortcutItem.localizedTitle); if ([shortcutItem.type isEqualToString:@"com.test.deep1"]) { [self launchViewController1]; } if ([shortcutItem.type isEqualToString:@"com.test.deep2"]) { [self launchViewController2]; } }
注意:
1、快捷标签最多可以创建四个,包括静态的和动态的。
2、每个标签的题目和icon最多两行,多出的会用…省略
Peek and Pop
Peek and Pop
实现 Peek 和 Pop 也非常简单,需要以下步骤:1、在需要预览的 ViewController 遵循并实现
UIViewControllerPreviewingDelegate协议
2、调用
- (id <UIViewControllerPreviewing>)registerForPreviewingWithDelegate:(id<UIViewControllerPreviewingDelegate>)delegate sourceView:(UIView *)sourceView NS_AVAILABLE_IOS(9_0)方法注册该 ViewController
3、在
- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location NS_AVAILABLE_IOS(9_0)代理方法中提供一个预览的 ViewController,并设置好 context 的 sourceRect.
4、在
- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit NS_AVAILABLE_IOS(9_0)方法中调用
- (void)showDetailViewController:(UIViewController *)vc sender:(nullable id)sender NS_AVAILABLE_IOS(8_0)
# pragma mark - UIViewControllerPreviewingDelegate - (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location { // check if we're not already displaying a preview controller if ([self.presentedViewController isKindOfClass:[PreviewViewController class]]) { return nil; } // shallow press: return the preview controller here (peek) UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *previewController = [storyboard instantiateViewControllerWithIdentifier:@"PreviewView"]; return previewController; } - (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit { // deep press: bring up the commit view controller (pop) UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *commitController = [storyboard instantiateViewControllerWithIdentifier:@"CommitView"]; [self showViewController:commitController sender:self]; }
注意:在开发 Peek and Pop 的过程中,请记住以下原则:
1、让合适的内容支持 Peek and Pop (不要滥用这项特性);
2、始终返回相同的预览界面 (保持一致性和可预测性);
3、不要在preview代理方法中花太多的时间;
4、为 context 设置正确的 sourceRect
Preview Action
在 Preview 的过程中,用户可以上滑来唤出类似 Action Sheet 的菜单。实现这一功能只需要重写 ViewController 中的- (NSArray <id <UIPreviewActionItem>> *)previewActionItems NS_AVAILABLE_IOS(9_0)方法即可。 系统提供了和 UIAlertAction 非常类似的 UIPreviewAction,来实现 UIPreviewActionItem。
与 Action Sheet 不同的是,系统提供了 UIPreviewActionGroup 类,实现子菜单的功能。
其中,
UIPreviewAction和
UIPreviewActionGroup的 API 很简单,类似于
UIAlertAction。
NS_CLASS_AVAILABLE_IOS(9_0) @protocol UIPreviewActionItem <NSObject> /// UIPreviewAction 的标题 @property(nonatomic, copy, readonly) NSString *title; @end typedef NS_ENUM(NSInteger,UIPreviewActionStyle) { UIPreviewActionStyleDefault=0, UIPreviewActionStyleSelected, UIPreviewActionStyleDestructive, } NS_ENUM_AVAILABLE_IOS(9_0); NS_CLASS_AVAILABLE_IOS(9_0) @interface UIPreviewAction : NSObject <NSCopying,UIPreviewActionItem> /// UIPreviewAction 的点击事件 @property(nonatomic, copy, readonly) void (^handler)(id<UIPreviewActionItem> action, UIViewController *previewViewController); + (instancetype)actionWithTitle:(NSString *)title style:(UIPreviewActionStyle)style handler:(void (^)(UIPreviewAction *action, UIViewController *previewViewController))handler; @end NS_CLASS_AVAILABLE_IOS(9_0) @interface UIPreviewActionGroup : NSObject <NSCopying,UIPreviewActionItem> + (instancetype)actionGroupWithTitle:(NSString *)title style:(UIPreviewActionStyle)style actions:(NSArray<UIPreviewAction *> *)actions; @end NS_ASSUME_NONNULL_END
Force Properties
iOS 9.0 之后,UITouch类中增加的一些新属性:
@property(nonatomic,readonly) UITouchType type
触摸的类型。
typedef NS_ENUM(NSInteger, UITouchType) { // 一个手指(在屏幕上)直接接触 UITouchTypeDirect, // 间接接触 UITouchTypeIndirect, // 触控笔接触 UITouchTypeStylus NS_AVAILABLE_IOS(9_1), } NS_ENUM_AVAILABLE_IOS(9_0);
@property(nonatomic,readonly) CGFloat force
触摸的压力值,其中 1.0 表示一个平均压力值(有系统预定,而不是用户自己设定)。
@property(nonatomic,readonly) CGFloat altitudeAngle
触控笔的高度(弧度)。
@property(nonatomic,readonly) CGFloat maximumPossibleForce
触摸的最大可能的压力值。
@property(nonatomic,readonly) UITouchProperties estimatedProperties
当前触摸对象估计的触摸特性。
typedef NS_OPTIONS(NSInteger, UITouchProperties) { // 压力除魔属性 UITouchPropertyForce = (1UL << 0), // 方位角除魔属性 UITouchPropertyAzimuth = (1UL << 1), // 海拔高度除魔属性 UITouchPropertyAltitude = (1UL << 2), // 位置除魔属性 UITouchPropertyLocation = (1UL << 3), // For predicted Touches } NS_AVAILABLE_IOS(9_1);
@property(nonatomic, readonly) CGFloat altitudeAngle
高度值,仅适用于触控笔触摸类型。当笔平行于平面时,该值为0;当笔垂直于平面时,该值为Pi / 2 。
@property(nonatomic,readonly) NSNumber * _Nullable estimationUpdateIndex
一个可以让你关联更新后的触摸和原始触摸的索引值,当每个触摸对象的触摸特性发生变化时,该值将会单独增加。
@property(nonatomic,readonly) UITouchProperties estimatedPropertiesExpectingUpdates- 一组触摸属性,希望在未来有传入的更新。如果没有预计属性的更新,当前值是最终的估计值。
iOS 9.0 之后,
UITouch类中增添的一些新方法:
- (CGPoint)preciseLocationInView:(UIView *)view;
当可用时,返回一个精确的触摸位置。
- (CGPoint)precisePreviousLocationInView:(UIView *)view;
当可用时,返回一个精确的前一个触摸位置。
- (CGFloat)azimuthAngleInView:(nullable UIView *)view
返回愁莫比的方位角(弧度)。
- (CGVector)azimuthUnitVectorInView:(UIView *)view;
返回触控笔的镇的方向上的而单位向量。
获取触摸压力值很简单:
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSArray *arrayTouch = [touches allObjects]; UITouch *touch = (UITouch *)[arrayTouch lastObject]; NSLog(@"%f",touch.force); }
附:模拟器 3D Touch 测试方法
在模拟器上是不能使用 3D Touch 功能的,但是难不倒万能的「程序员」。在 GitHub 上出现了一个可以在模拟器上实现 3D Touch 功能的插件 .SBShortcutMenuSimulator,具体使用方法还是移步 GitHub 自行查阅。相关文章推荐
- iOS9 3D Touch iOS 教程 ShortcutItem使用
- IOS 3Dtouch
- iOS 9 新特性之实现 3D Touch 就是 So easy -- OC版
- iOS 3D Touch功能
- ios 3D Touch
- iOS-如何集成iOS9里的3D Touch
- iOS开发-3DTouch开发
- iOS 3DTouch
- iOS 9 新特性之实现 3D Touch 就是 So easy -- OC版
- iOS 检查手机的3D Touch是否可用
- iOS 9 之 3D touch
- iOS开发之3D Touch
- iOS 3D Touch (UIApplicationShortcutItem、UIViewControllerPreviewing、UIPreviewAction)
- Xcode7.0 iOS 9.0 Touch 3d demo
- iOS 9 新特性之实现 3D Touch 就是 So easy -- OC版
- iPhone 6s极致体验:3D-Touch+iOS 9系统
- iOS 3D touch
- iOS 3d touch设计的秘密
- ios模拟器展示3D Touch
- iOS 9 spotlight搜索 3DTouch