iOS 利用長按手勢移動 Table View Cells

来源:http://www.cnblogs.com/jgCho/archive/2016/03/10/5262281.html
-Advertisement-
Play Games

本文譯自:Cookbook: Moving Table View Cells with a Long Press Gesture 目錄: 你需要什麼? 如何做? 如何將其利用至UICollectionView上? 何去何從? 本次的 cookbook-style 教程中介紹如何通過長按手勢來移動 t


本文譯自:Cookbook: Moving Table View Cells with a Long Press Gesture

目錄:

  • 你需要什麼?
  • 如何做?
  • 如何將其利用至UICollectionView上?
  • 何去何從?

本次的 cookbook-style 教程中介紹如何通過長按手勢來移動 table view中的cell,這種操作方式就像蘋果自家的天氣 App 一樣。

你可以直接把本文中的到嗎添加到你的工程中,或者將其添加到我為你創建好的 starter project 中,也可以下載本文的完整示例工程

你需要什麼?

  • UILongGestureRecognizer
  • UITableView (可以用 UICollectionView 替代之)
  • UITableViewController (可以用 UIViewController 或 UICollectionViewController 替代之)
  • 5 分鐘。

如何做?

首先給 table view 添加一個 UILongGestureRecognizer。可以在 table view controller 的 viewDidLoad 方法中添加。

1 2 3 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)]; [self.tableView addGestureRecognizer:longPress];

記者為 gesture recognizer 添加 action 方法。該方法首先應該獲取到在 table view 中長按的位置,然後找出這個位置對應的 cell 的 index。記住:這裡獲取到的 index path 有可能為 nil(例如,如果用戶長按在 table view的section header上)。

1 2 3 4 5 6 7 8 9 10 - (IBAction)longPressGestureRecognized:(id)sender {   UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender; UIGestureRecognizerState state = longPress.state;   CGPoint location = [longPress locationInView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];   // More coming soon... }

接著你需要處理UIGestureRecognizerStateBegan分支。如果獲取到一個有效的 index path(non-nil),就去獲取對應的 UITableViewCell,並利用一個 helper 方法獲取這個 table view cell 的 snapshot view。然後將這個 snapshot view 添加到 table view 中,並將其 center 到對應的 cell上。

為了更好的用戶體驗,以及更自然的效果,在這裡我把原始 cell 的背景設置為黑色,並給 snapshot view 增加淡入效果,讓 snapshot view 比 原始 cell 稍微大一點,將它的Y坐標偏移量與手勢的位置的Y軸對齊。這樣處理之後,cell 就像從 table view 中跳出,然後浮在上面,並捕捉到用戶的手指。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 static UIView *snapshot = nil; ///< A snapshot of the row user is moving. static NSIndexPath *sourceIndexPath = nil; ///< Initial index path, where gesture begins.   switch (state) { case UIGestureRecognizerStateBegan: { if (indexPath) { sourceIndexPath = indexPath;   UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];   // Take a snapshot of the selected row using helper method. snapshot = [self customSnapshotFromView:cell];   // Add the snapshot as subview, centered at cell's center... __block CGPoint center = cell.center; snapshot.center = center; snapshot.alpha = 0.0; [self.tableView addSubview:snapshot]; [UIView animateWithDuration:0.25 animations:^{   // Offset for gesture location. center.y = location.y; snapshot.center = center; snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05); snapshot.alpha = 0.98;   // Black out. cell.backgroundColor = [UIColor blackColor]; } completion:nil]; } break; } // More coming soon... }

將下麵的方法添加到 .m 文件的尾部。該方法會根據傳入的 view,返回一個對應的 snapshot view。

1 2 3 4 5 6 7 8 9 10 11 - (UIView *)customSnapshotFromView:(UIView *)inputView {   UIView *snapshot = [inputView snapshotViewAfterScreenUpdates:YES]; snapshot.layer.masksToBounds = NO; snapshot.layer.cornerRadius = 0.0; snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0); snapshot.layer.shadowRadius = 5.0; snapshot.layer.shadowOpacity = 0.4;   return snapshot; }

當手勢移動的時候,也就是UIGestureRecognizerStateChanged分支,此時需要移動 snapshot view(只需要設置它的 Y 軸偏移量即可)。如果手勢移動的距離對應到另外一個 index path,就需要告訴 table view,讓其移動 rows。同時,你需要對 data source 進行更新:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 case UIGestureRecognizerStateChanged: { CGPoint center = snapshot.center; center.y = location.y; snapshot.center = center;   // Is destination valid and is it different from source? if (indexPath && ![indexPath isEqual:sourceIndexPath]) {   // ... update data source. [self.objects exchangeObjectAtIndex:indexPath.row withObjectAtIndex:sourceIndexPath.row];   // ... move the rows. [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];   // ... and update source so it is in sync with UI changes. sourceIndexPath = indexPath; } break; } // More coming soon...

最後,當手勢結束或者取消時,table view 和 data source 都是最新的。你所需要做的事情就是將 snapshot view 從 table view 中移除,並把 cell 的背景色還原為白色。

為了提升用戶體驗,我們將 snapshot view 淡出,並讓其尺寸變小至與 cell 一樣。這樣看起來就像把 cell 放回原處一樣。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 default: { // Clean up. UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:sourceIndexPath]; [UIView animateWithDuration:0.25 animations:^{   snapshot.center = cell.center; snapshot.transform = CGAffineTransformIdentity; snapshot.alpha = 0.0;   // Undo the black-out effect we did. cell.backgroundColor = [UIColor whiteColor];   } completion:^(BOOL finished) {   [snapshot removeFromSuperview]; snapshot = nil;   }]; sourceIndexPath = nil; break; }

就這樣,搞定了!編譯並運行程式,現在可以通過長按手勢對 tableview cells重新排序!

你可以在 GitHub 上下載到完整的示例工程

如何將其利用至UICollectionView上?

假設你已經有一個示例工程使用了 UICollectionView,那麼你可以很簡單的就使用上本文之前介紹的代碼。所需要做的事情就是用 self.collectionView替換掉 self.tableView,並更新一下獲取和移動 UICollectionViewCell 的調用方法。

這裡有個練習,從 GitHub上 checkout 出 UICollectionView 的starter project,然後將 tap-和-hold 手勢添加進去以對 cells 進行重排。這裡可以下載到已經實現好了工程


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • iew controllers 通常是 iOS 項目中最大的文件,並且它們包含了許多不必要的代碼。所以 View controllers 中的代碼幾乎總是復用率最低的。我們將會看到給 view controllers 瘦身的技術,讓代碼變得可以復用,以及把代碼移動到更合適的地方。 你可以在 Gith
  • TextView 是個非常有用的組件,可使用XML來定義,也可使用程式代碼中的 Method方法來定義。 android:autoLink 設置是否當文本為URL鏈接/email/電話號碼/map時,文本顯示為可點擊的鏈接。可選值(none/web/email/phone/map/all) andr
  • 可能是由於粘貼網頁上的代碼的時候兩行之間的回車引起的,兩行之間重新輸入回車就行...。。。刪掉重新寫一遍就ok了
  • 個人筆記與總結。
  • 博客園官方API 花樣作死封裝網路層(iOS或OSX) === 前一段時間通過孤獨的貓咪神瞭解到博客園有官方API,據說今年四月份下旬的樣子推出吧。(道聽途說!)...我小小的申請去測試了下,打算也用博客園官方的API寫一點兒東西,例如OSX和iOS的小軟體。。在之前博客園官方的API也是公開的,舊
  • 我的天! 折騰了好久終於搭建成功了第一個項目。 項目環境: Windows 7 家庭普通版 64位 Android studio 1.5.1 OpenCV-2.4.9-android-sdk 基於Android studio上OpenCv開發環境的配置請參考 http://www.cnblogs.c
  • 最近開發android軟體客戶要安裝在樂視TV上,而且要求是開機自啟。我很天真的以為寫一個廣播接收類接收開機廣播就可以了,可是根本不會,有的設備就是不可以接收到開機廣播,於是各種百度搜索。大神們說是只有系統軟體才可以監聽到開機廣播,於是我要把自己的應用升級為系統應用..... 就先說如何將自己的應用
  • 本文譯自iOS 7 Blur Effects with GPUImage。 iOS 7在視覺方面有許多改變,其中非常吸引人的功能之一就是在整個系統中巧妙的使用了模糊效果。許多第三方應用程式已經採用了這樣的設計細節,並以各種奇妙的和具有創造性的方式使用它。 本文將通過幾種不同的技術來實現iOS 7中的
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...