PaperLike

上周有翻译到一篇关于使用Layout实现可拖拽的CollectionView的英文博客,之后就去大概实现了一下Facebook Paper的Paper选择页,大概界面是这样的

上下的标签可以互相拖拽。

因此,我们这次的目标就是实现在两个CollectionView中拖拽一个Cell。

我在Github上已经粗糙的实现了一下,当然这个上面还包含了Paper的其他页面,但是我们这次只介绍关于如何实现在两个CollectionView中拖拽一个Cell的部分。

先实现上周的效果

我们首先先实现上周介绍的,在单一的CollectionView中的拖拽,这次我们使用Objective-C来实现。</br>
首先我们要有一个Bundle来记录和被拖拽的Cell相关的属性。

@interface Bundle : NSObject
@property (assign, nonatomic) CGPoint offset;
@property (strong, nonatomic) UICollectionViewCell *sourceCell;
@property (strong, nonatomic) UIView *representationImageView;
@property (strong, nonatomic) NSIndexPath *currentIndexPath;
@end

定义Layout并命名为RearrangeableCollectionViewFlowLayout,大致代码为:

@property (assign, nonatomic) BOOL animating;
//@property (strong, nonatomic) NSIndexPath *currentIndexPath;
@property (assign, nonatomic) CGRect collectionViewFrameInCanvas;
@property (strong, nonatomic) NSMutableDictionary *hitTestRectagles;
@property (strong, nonatomic) UIView *canvas;
@property (strong, nonatomic) Bundle *bundle;
@property (strong, nonatomic) MoveItemData moveItemData;

和上周翻译的文章里介绍的不同的是,我们这里使用一个Block:

typedef void (^MoveItemData)(NSIndexPath *fromIndexPath, NSIndexPath *toIndexPath);

在Cell交换位置的时候进行数据的对换。

实现文件

实现文件中,比那篇英文翻译中多了一个hasAddLongPressGesture变量,这个变量初始化为NO,当加上了手势之后变为YES。防止多次加手势导致内存的滥用。</br>

- (void)setup中加入手势,初始化傀儡拖拽Cell的父View(canvas)。</br>
- (void)prepareLayoutsetup并计算两边的触发滚动区域。</br>
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer中判断是否在点击某个Cell并对Bundle初始化。</br>
- (void)handleGestureBegan:(UILongPressGestureRecognizer *)gesture中隐藏原Cell并在canvas中加入傀儡cell。</br>
- (void)handleGestureChanged:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas中根据手势移动傀儡Cell。得到移动位置对应的Cell的indexPath,并和之前的IndexPath进行比较,进行必要的Cell位置对换。</br>
- (void)handleGestureEnded:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas中用动画返回cell对应的位置。

那么这样我们将这个Layout赋值个某个CollectionView的Layout的时候,这个CollectionView就能够实现长按移动Cell的功能了。

进一步实现

解决完了上面的问题,那么问题接着来了,我们怎么能够实现两个CollectionView都因为一个Cell而动起来,并且这个Cell能够在两个CollectionView之间传递。

其实最好的办法还是能够把关于拖拽的东西写到另一个类中,这样这个拖拽的功能就和这个CollectionView的耦合度更低。然而我还是懒得想,就都放在了这个Layout中。

这样我们就有两个CollectionView:collectionview1和collectionview2。已经两个FlowLayout:layout1和layout2。我们可以想象,里那个歌Layout必须公用一些数据,也就是手势信息。当一个layout命令它对应的Cell做一些事情的时候,另一个layout也要做一些事情来响应这相同的手势,所以,我决定将手势的信息在两个layout之间传递。
当然,传递的方式有三种,1、直接通过方法调用并传递参数,2、使用Block的方法传递参数,3、使用Delegate的方法传递参数。
这里我们使用Block加方法调用的方式传递参数,当然delegate是完全可行的,这些只是脑子里灵光一现的事情~~爱用什么用什么。

Blocks

我们要使用这些Block:

typedef void (^FinishAnimationForCellMove)();
typedef void (^DeleteItemData)(NSIndexPath *indexPath);
typedef void (^AddItemData)(NSIndexPath *indexPath);
typedef void (^SendGestureBeganOut)(UILongPressGestureRecognizer *gesture);
typedef void (^SendGestureChangedOut)(UILongPressGestureRecognizer *gesture, CGPoint dragPointOnCanvas);
typedef void (^SendGestureEndedOut)(UILongPressGestureRecognizer *gesture, CGPoint dragPointOnCanvas);
typedef BOOL (^CheckIfBack)(CGPoint drag);
typedef void (^SendIfShouldBeganGesture)(Bundle *bundle);
typedef void (^SendIfShouldFlyToOthers)();

FinishAnimationForCellMove定义我们在最后动画结束之后应该移动Cell。
DeleteItemData定义当我们删除Cell之后应该删除数据。AddItemData定义当我们加入Cell之后应该添加数据,SendGestureBeganOut定义当手势要开始的时候的该干什么,要将手势传递出去,同理SendGestureEndedOut, SendGestureChangedOut都是定义手势发生变化的时候外面该干什么,SendIfShouldBeganGesture在手势开始缠身Bundle的时候将Bundle传出去共享部分信息,CheckIfBack通过最后手指的位置返回是否需要返回或是飞到另一个CollectionView上去,SendIfShouldFlyToOthers通知Cell做动画飞到另一个CollectionView上去。

Public Function

接下来就是一些对外的方法

- (void)publicHandleGestureBegan:(UILongPressGestureRecognizer *)gesture;
- (void)publicHandleGestureChanged:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas;
- (void)publicHandleGestureEnded:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas;
- (void)publicAnimationAddCell;

- (void)publicHandleGestureBegan:(UILongPressGestureRecognizer *)gesture当另一个Cell被手势产生GestureBegan的时候通过BlockSendGestureBeganOut命令当前CollectionView做一些事情。
同理

- (void)publicHandleGestureChanged:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas;
- (void)publicHandleGestureEnded:(UILongPressGestureRecognizer *)gesture dragPointOnCanvas:(CGPoint)dragPointOnCanvas;

的作用差不多</br>

- (void)publicAnimationAddCell;是当另一个CollectionView的Cell飞到当前CollectionView的时候的动画

大致的实现差不多就是这样。详细实现还是在代码中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容