转载

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

Paste configuration

我们都知道, 在iOS有一个东西叫做UIMenuController, 它是一个单例, 可以方便我们简单的去做一些复制, 粘贴等等的操作, 但在iOS 11这个粘贴功能进化了, 让我们一起来看看吧, 首先我们要有一个工程项目:

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

简单显示的东西就好.

然后呢, 我们需要有一个用手势操作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 *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 *)itemProviders {
    for (NSItemProvider *item in itemProviders) {
        [item loadObjectOfClass:TableViewCellModel.class
              completionHandler:^(id  _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:

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

这里我们要介绍两个新的代理UITableViewDragDelegate, 和UITableViewDropDelegate, 一个分别拖动, 一个分别是放下的代理.

这里我们要声明一个遵守了NSItemProviderReading, NSItemProviderWriting的Model, 内部实现在工程里查看:

最终我们去实现拖放功能的就是要去实现那两个代理的方法:

#pragma mark - Table View Drag Delegate
- (NSArray *)tableView:(UITableView *)tableView
        itemsForBeginningDragSession:(id)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)coordinator {
    if (!coordinator) {
        return;
    }
    NSIndexPath *destinationIndexPath = coordinator.destinationIndexPath;
    dispatch_async(dispatch_get_main_queue(), ^{
        [tableView performBatchUpdates:^{
            [coordinator.items enumerateObjectsUsingBlock:^(id  _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)session {
    return [session canLoadObjectsOfClass:ListModel.class];
}
- (UITableViewDropProposal *)tableView:(UITableView *)tableView
                  dropSessionDidUpdate:(id)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;
}

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

关于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:

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

然后添加自己喜欢的颜色值:

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

这里我们要看看两个API, 都是在iOS 11之后才出来的

+ (nullable UIColor *)colorNamed:(NSString *)name
+ (nullable UIColor *)colorNamed:(NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection

最终效果:

玩转iOS开发:iOS 11 新特性《UIKit新特性的基本认识》

新添加的辅助功能

在讲这个得时候, 这里是需要装有iOS 11的真机设备.

但由于我现在手上没有iOS 11的设备, 所以这里暂时不说, 有兴趣的话, 可以到百度去搜搜, 或者等我iOS 11设备的时候再更新吧.

总结

在iOS 11更多的东西都是在优化和改进开发的流程, 这篇张文章只是简单的介绍一下而已, 还有更多更深层次的可以自行去查阅苹果的官方文档, 或者是去看看WWDC的视频演示:

工程地址

项目地址: github.com/CainRun/iOS…

正文到此结束
Loading...