本文译自: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 进行重排。这里可以下载到已经实现好了工程

iOS 利用长按手势移动 Table View Cells的更多相关文章

  1. Table View Programming Guide for iOS---(六)---A Closer Look at Table View Cells

    A Closer Look at Table View Cells A table view uses cell objects to draw its visible rows and then c ...

  2. Table View Programming Guide for iOS---(一)---About Table Views in iOS Apps

    About Table Views in iOS Apps Table views are versatile user interface objects frequently found in i ...

  3. 创建一个Table View

    在本课程中,您将创建应用程序FoodTracker的主屏幕.您将创建第二个,表视图为主场景,列出了用户的菜谱.你会设计定制表格单元格显示每一个菜谱,它是这样的: 学习目标 在课程结束时,你将能够: 创 ...

  4. How To Make A Swipeable Table View Cell With Actions – Without Going Nuts With Scroll Views

    How To Make A Swipeable Table View Cell With Actions – Without Going Nuts With Scroll Views  Ellen S ...

  5. Table View Programming Guide for iOS---(七)---Managing Selections

    Managing Selections 管理选择 When users tap a row of a table view, usually something happens as a result ...

  6. Table View Programming Guide for iOS---(五)---Creating and Configuring a Table View

    Creating and Configuring a Table View Your app must present a table view to users before it can mana ...

  7. Table View Programming Guide for iOS---(三)----Overview of the Table View API

    Overview of the Table View API 表格视图API概述 The table view programming interface includes several UIKit ...

  8. Table View Programming Guide for iOS---(二)----Table View Styles and Accessory Views

    Table View Styles and Accessory Views 表格视图的风格以及辅助视图 Table views come in distinctive styles that are ...

  9. iOS学习之Table View的简单使用

    Table View简单描述: 在iPhone和其他iOS的很多程序中都会看到Table View的出现,除了一般的表格资料展示之外,设置的属性资料往往也用到Table View,Table View ...

随机推荐

  1. 关于js中的回收机制,通俗版

    在前面的几篇文章中,我讲解过了js中的回收机制,但是对于当时的我来说,我自己对回收机制的这个概念也有些懵懵懂懂,现在对回收机制有了更深入的理解,所以特此发布此文给于总结,也好加深记忆. 如果你想学习闭 ...

  2. oo智慧

    单一职责:学 寝室不能学习,学习要去教室 开闭原则:美 爱美穿衣打扮是扩展 整容是修改,修改有风险,所以对扩展开放,对修改封闭 里氏替换:死 人会死,你是人,你会死 依赖倒置:钱 一切向钱看,钱是抽象 ...

  3. 爬虫技术 -- 进阶学习(八)模拟简单浏览器(附c#代码)

    由于最近在做毕业设计,需要用到一些简单的浏览器功能,于是学习了一下,顺便写篇博客~~大牛请勿喷,菜鸟练练手~ 实现界面如下:(简单朴素版@_@||) button_go实现如下: private vo ...

  4. [Math] Deferred Acceptance Algorithm

    约会配对问题 一.立即接受算法: 对于约会的配对,大家都去追自己最心仪的女生.而这个女生面对几位追求者,要立刻做个决定. 被拒绝的男生们调整一下心情,再去追求心中的 No. 2.以此类推. 这样做法有 ...

  5. Tips1:用 Export Package选项来分享你的成果

    如果你不是一个人工作,你可能需要和其他人共享一个工程文件,Unity工程文件中的一些关键元素默认是隐藏的,因此通过复制Assets文件夹的方法并不完善.Unity自带的UnityPackage格式的文 ...

  6. webapp,liveapp: 流式布局和rem布局

    liveapp场景应用,一般针对的是移动端,近来也是很火,颇有一些感受,拿来分享一下. 页面宽度范围: 一般移动端页面我们的像素范围是320px-640px,最大640px,最小320px,所以设计稿 ...

  7. UWP开发入门(十四)—— UserControl中Adaptive UI的小技巧

    本篇我们通过绘制一个非常简单的UserControl控件,来分享一下对Adaptive UI的理解及一些图形绘制的技巧. 现在流行的APP都少不了精致的用户头像,首先假设我们需要绘制如下的图形作为默认 ...

  8. Qt之QAbstractItemView右键菜单

    一.功能概述 说起右键菜单,之前Qt之自定义QLineEdit右键菜单这篇文章中我已经讲述过3种右键菜单的实现方式,今儿也是在啰嗦一下,针对QListWidget类在定制一下右键菜单,我使用的具体方式 ...

  9. SQL Server中中数据行批量插入脚本的存储实现

        看到博友SQL Server MVP桦仔的一篇博文“将表里的数据批量生成INSERT语句的存储过程的实现”.我仔细看来博文中的两个存储代码,自我感觉两个都不太满意,都是生成的单行模式的插入,数 ...

  10. 【Win10】【Win2D】实现控件阴影效果

    学过 WPF 的都知道,在 WPF 中,为控件添加一个阴影效果是相当容易的. <Border Width="100" Height="100" Backg ...