文章分享至我的个人技术博客: https://cainluo.github.io/15099354591154.html
前两篇, 我们讲了Xcode 9
的一些新特性, 可以更加方便我们去写"bug
".
如果没有看的朋友可以去看看:
那么这一次呢, 我们来简单的了解一下, 在iOS 11
里, UIKit
更新了一些什么东西, 可以让我们更加快捷的开发.
转载声明:如需要转载该文章, 请联系作者, 并且注明出处, 以及不能擅自修改本文.
Paste configuration
我们都知道, 在iOS
有一个东西叫做UIMenuController
, 它是一个单例, 可以方便我们简单的去做一些复制, 粘贴等等的操作, 但在iOS 11
这个粘贴功能进化了, 让我们一起来看看吧, 首先我们要有一个工程项目:
简单显示的东西就好.
然后呢, 我们需要有一个用手势操作UIMenuController
的管理者MenuManager
, 详细的代码都在工程里, 大家可以去看看.
在iOS 11
的时候, 苹果推出了一个东西叫做UIPasteConfiguration
, 它是直接继承NSObject
官方解释:
The interface that an object implements to declare its ability to accept specific data types for pasting and for drag and drop activities.
这个东西能用来干嘛呢?
配置粘贴功能
在项目里, 我们默认给TableView
加了长按手势和点击手势, 便于用来控制UIMenuController
.
为了方便演示这个配置粘贴的功能, 另外多开了一个控制器, 这里我们需要声明一个全局字符串, 为的就是用来给这个粘贴功能加个唯一的标识:
@property (nonatomic, copy) NSArray<NSString *> *acceptableTypeIdentifiers;
复制代码
添加了这个唯一标识, 我们就需要在Cell
里给copy:
的方法加点修改:
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action
withSender:(id)sender {
return action == @selector(copy:);
}
- (void)copy:(id)sender {
if (self.model == nil) {
return;
}
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.model];
[[UIPasteboard generalPasteboard] setData:data
forPasteboardType:CELL_TYPE];
}
复制代码
这里面的CELL_TYPE
就是全局的唯一标识.
还有就是要在需要粘贴功能的控制器PasteViewController
里也配置一下:
UIPasteConfiguration *pasteConfiguration = [[UIPasteConfiguration alloc] initWithAcceptableTypeIdentifiers:@[CELL_TYPE]];
self.pasteConfiguration = pasteConfiguration;
复制代码
并且这里我们还要重写一个方法:
- (void)pasteItemProviders:(NSArray<NSItemProvider *> *)itemProviders {
for (NSItemProvider *item in itemProviders) {
[item loadObjectOfClass:TableViewCellModel.class
completionHandler:^(id<NSItemProviderReading> _Nullable object, NSError * _Nullable error) {
if (object) {
TableViewCellModel *model = (TableViewCellModel *)object;
dispatch_async(dispatch_get_main_queue(), ^{
self.targetTextField.text = [NSString stringWithFormat:@"复制的内容: %@", model.titleString];
});
}
}];
}
}
复制代码
用来处理粘贴后的数据.
PS: 这里的TableViewCellModel
是需要遵守一个NSItemProviderReading
协议, 并且在内部实现它的协议方法, 详情可以去代码里看看.
拖放的基本认识
在iOS 11
, 苹果爸爸终于把拖放的功能添加进来了, 但这个功能真正受益的是iPad
, 它可以在分屏App
里实现数据复制和移动, 甚至还可以共享.
我们在拖动的过程中, 数据会被序列化, 然后呈现在用户拖动的系统控制预览中, 在拖动完成后, 序列化的数据会被复制到目的地, 然后反序列化, 最终将这些信息呈献给用户.
而最先获得支持的两个控件就是UITableView
和UICollectionView
. 现在让我们来新建个工程看看是如何操作.
这里我们还是一个简单的TableView
:
这里我们要介绍两个新的代理UITableViewDragDelegate
, 和UITableViewDropDelegate
, 一个分别拖动, 一个分别是放下的代理.
这里我们要声明一个遵守了NSItemProviderReading
, NSItemProviderWriting
的Model
, 内部实现在工程里查看:
最终我们去实现拖放功能的就是要去实现那两个代理的方法:
#pragma mark - Table View Drag Delegate
- (NSArray<UIDragItem *> *)tableView:(UITableView *)tableView
itemsForBeginningDragSession:(id<UIDragSession>)session
atIndexPath:(NSIndexPath *)indexPath {
ListModel *model = self.dataSource[indexPath.row];
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:model];
UIDragItem *dragItem = [[UIDragItem alloc] initWithItemProvider:itemProvider];
return @[dragItem];
}
#pragma mark - Table View Drop Delegate
- (void)tableView:(UITableView *)tableView
performDropWithCoordinator:(id<UITableViewDropCoordinator>)coordinator {
if (!coordinator) {
return;
}
NSIndexPath *destinationIndexPath = coordinator.destinationIndexPath;
dispatch_async(dispatch_get_main_queue(), ^{
[tableView performBatchUpdates:^{
[coordinator.items enumerateObjectsUsingBlock:^(id<UITableViewDropItem> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (!obj) {
return;
}
NSIndexPath *indexPath = obj.sourceIndexPath;
ListModel *model = self.dataSource[indexPath.row];
[self.dataSource removeObject:model];
[self.dataSource insertObject:model
atIndex:destinationIndexPath.row];
[tableView moveRowAtIndexPath:indexPath
toIndexPath:destinationIndexPath];
}];
} completion:nil];
});
}
- (BOOL)tableView:(UITableView *)tableView
canHandleDropSession:(id<UIDropSession>)session {
return [session canLoadObjectsOfClass:ListModel.class];
}
- (UITableViewDropProposal *)tableView:(UITableView *)tableView
dropSessionDidUpdate:(id<UIDropSession>)session
withDestinationIndexPath:(nullable NSIndexPath *)destinationIndexPath {
return [[UITableViewDropProposal alloc] initWithDropOperation:UIDropOperationMove
intent:UITableViewDropIntentInsertAtDestinationIndexPath];
}
复制代码
代码写完了之后, 别忘了把TableView
的拖放功能给打开:
_tableView.dragInteractionEnabled = YES;
复制代码
效果图这里就不放了, 自己去跑跑Demo
就好了, 个人认为自己写的代码还是挺规整的~~哈哈
更详细的内容会在后续的文章慢慢讲解.
TableView侧边栏的改进
在iOS 8
的时候, 苹果爸爸就为TableView
引进了侧边栏的功能, 叫做UITableViewRowAction
, 不过在iOS 11
的时候, 苹果爸爸又增加了一个更加灵活的东西, 叫做UISwipeActionsConfiguration
:
我们另外建一个工程来看看, 然后实现我们的配置:
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *contextualAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
title:@"Add"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"Add");
}];
contextualAction.backgroundColor = [UIColor brownColor];
UISwipeActionsConfiguration *swipeActionsCOnfiguration = [UISwipeActionsConfiguration configurationWithActions:@[contextualAction]];
return swipeActionsCOnfiguration;
}
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView
leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *contextualAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
title:@"Copy"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"Copy");
}];
contextualAction.backgroundColor = [UIColor blackColor];
UISwipeActionsConfiguration *swipeActionsCOnfiguration = [UISwipeActionsConfiguration configurationWithActions:@[contextualAction]];
return swipeActionsCOnfiguration;
}
复制代码
关于TableView
刷新的时候, 我们还有一个专门的API
:
- (void)performBatchUpdates:(void (NS_NOESCAPE ^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL finished))completion API_AVAILABLE(ios(11.0), tvos(11.0));
复制代码
刚刚的拖放功能也是在这里面完成刷新数据源的, 这么做的话, 可以让我们的逻辑结构更加的清晰, 这样子我们也需要在使用dispatch_async(dispatch_get_main_queue(), ^{});
去更新了, 爽爽滴~~
Asset UIColor的集成
在Xcode 9
里, Asset
里可以集成UIColor
的目录, 这样子我们就可以省略声明一大堆的颜色, 详细怎么做呢? 我们一起来看看, 这里随便弄一个项目就好了.
然后我们在Assets.xcassets
里添加Color Set
:
然后添加自己喜欢的颜色值:
这里我们要看看两个API
, 都是在iOS 11
之后才出来的
+ (nullable UIColor *)colorNamed:(NSString *)name
+ (nullable UIColor *)colorNamed:(NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection
复制代码
最终效果:
新添加的辅助功能
在讲这个得时候, 这里是需要装有iOS 11
的真机设备.
但由于我现在手上没有iOS 11
的设备, 所以这里暂时不说, 有兴趣的话, 可以到百度去搜搜, 或者等我iOS 11
设备的时候再更新吧.
总结
在iOS 11
更多的东西都是在优化和改进开发的流程, 这篇张文章只是简单的介绍一下而已, 还有更多更深层次的可以自行去查阅苹果的官方文档, 或者是去看看WWDC
的视频演示:
- Cococa Touch中的新功能:apple.co/2vy2mOo
- 更新iOS 11的应用程序:apple.co/2syu3Tt
- 无障碍新功能:apple.co/2r9EASD
工程地址
项目地址: https://github.com/CainRun/iOS-11-Characteristic/tree/master/2.UIKit