文章分享至我的個人技術部落格: 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