大年初一,在家无事
甚是无聊,撰文一篇
自苹果在2015年发布3DTouch功能以来
iPhone 6s之后的机型全都匹配了3DTouch功能
说来惭愧
还没自己写过3DTouch相关的代码
于是研究了一波
我的研究大概包括以下三个方面:
- 在应用icon上呼出3DTouch菜单
- 在程序内部的Peek和Pop
- Widget开发
一: 在应用icon上呼出3DTouch菜单
搞出这种效果有两种方式:
- 在plist里面添加字段
- 在didFinishLaunchingWithOptions中用代码添加
第1种方式 : 在plist里面添加字段:
UIApplicationShortcutItemTitle : 必有用作按钮的标题
UIApplicationShortcutItemSubtitle : 非必有,用作按钮子标题
UIApplicationShortcutItemType : 必有,根据这个字段来判断点了哪个按钮
UIApplicationShortcutItemIconFile : 非必有, 图片的名字(自定义)
UIApplicationShortcutItemIconType :非必有, 图片的类型(系统提供)
UIApplicationShortcutItemUserInfo : 非必有,设置用户信息,是一个字典类型,可以用来传值
说明 :
少了任意必有项,这个按钮都不显示
UIApplicationShortcutItemIconFile和UIApplicationShortcutItemIconType必有其一
最多创建四个按钮
UIApplicationShortcutItemIconType的类型 :
// Override point for customization after application launch.
/**
*
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;
*/
第2种方式 : 在didFinishLaunchingWithOptions中用代码添加
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//自定义3DTouch按钮
UIApplicationShortcutItem *item1 = [[UIApplicationShortcutItem alloc]initWithType:@"4" localizedTitle:@"自定义标题1" localizedSubtitle:@"子标题4" icon:[UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeMail] userInfo:nil];
UIApplicationShortcutItem *item2 = [[UIApplicationShortcutItem alloc]initWithType:@"5" localizedTitle:@"自定义标题2" localizedSubtitle:@"子标题5" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:@"icon"] userInfo:nil];
[UIApplication sharedApplication].shortcutItems = @[item1,item2];
return YES;
}
item1是用系统提供的图片
item2是用自定义图片
很简单
然后就是按钮的监听:
//点击按钮进入
- (void)application:(UIApplication *)application performActionForShortcutItem:(nonnull UIApplicationShortcutItem *)shortcutItem completionHandler:(nonnull void (^)(BOOL))completionHandler {
if ([shortcutItem.type isEqualToString:@"1"]) {
//相应的处理
}else if ([shortcutItem.type isEqualToString:@"2"]) {
//相应的处理
}else {
//相应的处理
}
}
二: 在程序内部的Peek和Pop
大多数用在tableView上
先看效果图:
要实现这个效果
得先在TableViewController里面给cell注册一下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath];
cell.textLabel.text = self.dataArray[indexPath.row];
//想要peek 需要注册一下
[self registerForPreviewingWithDelegate:self sourceView:cell];
return cell;
}
然后遵循UIViewControllerPreviewingDelegate协议
实现这个方法
返回peek的的控制器
- (nullable UIViewController *)previewingContext:(id )previewingContext viewControllerForLocation:(CGPoint)location {
//location 是以cell为坐标系的坐标
//转换成以tableview为坐标系的坐标
CGPoint point = [self.tableView convertPoint:location fromView:[previewingContext sourceView]];
//这样就可以取到我点了第几行cell
NSIndexPath *index = [self.tableView indexPathForRowAtPoint:point];
return [[WebViewController alloc]init];
}
当再用力按的时候,就把这个控制器pop进来
//pop
//使劲一按 就push
- (void)previewingContext:(id )previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
//viewControllerToCommit 上个方法返回的vc
[self.navigationController pushViewController:viewControllerToCommit animated:NO];
}
如果想添加操作按钮
需要在将要弹出的控制器添加这个方法 :
- (NSArray> *)previewActionItems {
UIPreviewAction *item1 = [UIPreviewAction actionWithTitle:@"赞" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"点赞");
}];
UIPreviewAction *item2 = [UIPreviewAction actionWithTitle:@"踩" style:UIPreviewActionStyleSelected handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"点踩");
}];
UIPreviewAction *item3 = [UIPreviewAction actionWithTitle:@"X" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NSLog(@"点X");
}];
// UIPreviewActionGroup *group = [UIPreviewActionGroup actionGroupWithTitle:@"组" style:UIPreviewActionStyleDefault actions:@[]];
return @[item1,item2,item3];
}
还有值得说的一点就是UITouch对象添加了force
是一个记录按压力量的变量
取值是0~6.666
我们可以在touchesMoved里面打印一下
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *t =touches.anyObject;
NSLog(@"按压力量 - %f",t.force);
}
三: Widget开发
先上效果图 :
创建Widget
这个时候,你会看到项目目录里面多了
如果习惯纯代码开发,可以删掉storyboard
在控制器里随便添加点东西
运行就能看到效果了
如果想让Widget可以展开
就像这样:
可以添加以下代码:
//改为扩充模式(添加拓展按钮)
- (void)viewWillAppear:(BOOL)animated {
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize{
if (activeDisplayMode == NCWidgetDisplayModeCompact) {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 105);
}else {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 500);
}
}
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResultFailed
// If there's no update required, use NCUpdateResultNoData
// If there's an update, use NCUpdateResultNewData
completionHandler(NCUpdateResultNewData);
}
事件监听:
因为Widget是一个独立的小应用
所以需要添加:
主项目里面的AppDelegate:
//在widget进入
- (BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary *)options {
if ([url.description hasPrefix:@"widgetMain://"]) {
NSLog(@"%@", url.description);
//一些操作
}
return YES;
}
证书:
首先因为Widget是一个独立的小应用
因此证书也需要另外的一套
Bundle ID:widget的Bundle Id是在主项目的Bundle ID的基础上加的,例
主项目:
com.dx.widgetTestMain
widget:
com.dx.widgetTestMain.widgetTest
widget的App ID创建的时候要配置 App Groups项,例:
在创建APP ID的时候
勾选App Groups即可
创建APP ID之后,需要去创建一个App Groups
在项目中还需要配置之前给Widget添加的App Groups
如果widget里面要使用主项目里面的类,需要做下面操作:
感谢阅读
你的支持是我写作的唯一动力