拖动并交换两个View位置的一种思路

2018.08.13更新:
当当当当,良辰美景冒泡日~
闲暇时分,老夫把Demo用纯代码写了一遍,并且加入了自动滚动,核心思路并没有改变,新的效果图如下:

自动滚动.gif

希望能给小伙伴带来一些帮助~
Demo地址:https://github.com/Calabash-Boy/CB_DragView


父老乡亲们,好久不见,想死你们了~
世界杯正当火热,每天我家天台都熙熙攘攘,人来人往,好生热闹,而我看好的球队不出所料,都一一回家了...


宝宝心里苦

闲话于此,公司最近要做一个需求,客户预定酒店的时候可以自己决定来入住哪个房间,并且和谁一个房间🤩😏,想想果然有些小激动,demo实现的效果如下:


drag.gif

在网上查询了一下,大部分都是tableViewCell的交换,并不能很好的满足这个需求,因此尝试自己写了一种思路;
Demo地址:https://github.com/Calabash-Boy/CB_DragView
如果喜欢,烦请各位大佬赏个小星星😏~

思路如下:
  • 给每个可能拖动的View添加一个长按手势;
  • 手势触发的时候对该View(称之为fromView)进行截图,我们在拖动的过程中也是对这个截图进行操作,并且隐藏fromView;
  • 手势结束的时候,判断手势点的位置,有两种情况:
    1.在某个可拖动View上,我们称之为toView,隐藏toView,对toView截图并使其截图移动到fromView的位置,fromView下沉到toView的位置,并且交换数据源中相关的数据,更新界面,当两个截图交换的动画结束后,重新展示出fromViewtoView;
    2.不在任何一个可拖动View上,截图回归原位,fromView显示;
关键代码如下:
  • 注意其中坐标转换的代码,要把出发View和落脚View的fram转化到当前操作View的坐标系中;
- (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)longPress {
    
    //首先校验当前的Menu是否可以拖动
    CB_MenuView *menu = (CB_MenuView *)longPress.view;
    UILabel *dataLabel = [menu viewWithTag:110];
    if (!dataLabel.text.length) return;
    
    //当前手指的位置
    CGPoint currentPoint = [longPress locationInView:self];

    if (longPress.state == UIGestureRecognizerStateBegan) {
        //记录刚开始的时候View的位置
        //一定要把menu的坐标转换到自己的坐标系上
        CGRect rect = [menu.superview convertRect:menu.frame toView:self]; 
        self.fromCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
        self.fromView = menu;
        self.fromIndex = [_menuViewArray indexOfObject:menu];
        [self beginDragAnimation];
    }
    else if (longPress.state == UIGestureRecognizerStateChanged) {
        //拖动过程中移动动画View
        [UIView animateWithDuration:0.1 animations:^{
            CGPoint screenshotViewCenter = self.screenshotView.center;
            screenshotViewCenter.y = currentPoint.y;
            self.screenshotView.center = screenshotViewCenter;
        }];
    
    }
    else {
        self.toView = nil;
        CGRect rect = CGRectZero;
        //拖动结束 查看结束的位置是否处于某个Menu中 如果是 则交换位置
        for (CB_MenuView *menu in _menuViewArray) {
            rect = [menu.superview convertRect:menu.frame toView:self];
            if (CGRectContainsPoint(rect, currentPoint)) {
                self.toView = menu;
                self.toIndex = [_menuViewArray indexOfObject:menu];
                break;
            }
        }
        
        [self endDragAnimation];
    }
}
  • 开始动画的代码,注意此处的截图方法是一个分类,demo中可查看;
- (void)beginDragAnimation {
    if (self.screenshotView) {
        [self.screenshotView removeFromSuperview];
        self.screenshotView = nil;
    }
    //产生拖动的截图 隐藏原有截图
    UIView *screenshotView = [self.fromView screenshotViewWithShadowOpacity:0.3 shadowColor:[UIColor blackColor]];
    [self addSubview:screenshotView];
    [self bringSubviewToFront:screenshotView];
    self.screenshotView = screenshotView;
    self.screenshotView.center = self.fromCenter;
    self.fromView.hidden = YES;
    self.screenshotView.transform = CGAffineTransformMakeScale(1.03, 1.03);
}
  • 结束动画的代码;
- (void)endDragAnimation {
    if (self.toView) {
        CGRect rect = [self.toView.superview convertRect:self.toView.frame toView:self];
        self.toCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
        //截图 然后交换位置
        UIView *screenshotToView = [self.toView screenshotViewWithShadowOpacity:0.3 shadowColor:[UIColor blackColor]];
        [self addSubview:screenshotToView];
        [self insertSubview:screenshotToView belowSubview:self.screenshotView];
        self.toView.hidden = YES;
        screenshotToView.center = self.toCenter;
        screenshotToView.transform = CGAffineTransformMakeScale(1.03, 1.03);
        
        //此时去交换数据 更新界面
        [self exchangeData];

        //交换位置
        [UIView animateWithDuration:0.3 animations:^{
            //toView -> fromView
            screenshotToView.center = self.fromCenter;
            screenshotToView.transform = CGAffineTransformIdentity;
            
            //fromView -> toView
            self.screenshotView.transform = CGAffineTransformIdentity;
            self.screenshotView.center = self.toCenter;
            
        } completion:^(BOOL finished) {
            [screenshotToView removeFromSuperview];
            self.toView.hidden = NO;
            
            [self.screenshotView removeFromSuperview];
            self.screenshotView = nil;
            self.fromView.hidden = NO;
        }];
    } else {
        //不在任何一个位置 返回原处
        [UIView animateWithDuration:0.3 animations:^{
            self.screenshotView.transform = CGAffineTransformIdentity;
            self.screenshotView.center = self.fromCenter;
        } completion:^(BOOL finished) {
            [self.screenshotView removeFromSuperview];
            self.screenshotView = nil;
            self.fromView.hidden = NO;
            
        }];
    }
}
多说几句:
  • 本demo只提供一种交换动画的思路,对数据源的操作以及界面更新请按实际业务进行变更;
  • demo中的某些方法只是我为了快速完成测试而写,大家可以在注释处查看;
  • 本demo在移动过程中只更改了截图的y值,可以根据实际需要更改x的值;
  • 非常感谢下面这篇文章的思路和代码,截图的代码就是出自该demo;
    链接地址: https://www.jianshu.com/p/ef0d355f2cb4
  • 后续如果有时间会尝试写一个轮子;
  • 我! 看! 好! 西! 班! 牙! 夺! 冠!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容