iOS - 移动自定义UITableViewCell

原创 2016年08月29日 15:11:49

这里写图片描述
1.长按即可触发移动cell,操作逻辑简单;
2.移动cell时越靠近屏幕边缘,速度越快;
3.被移动cell的样式可以自定义;
调研

如果只是实现移动UITableViewCell,系统自带的API即可搞定。
调用下面的方法[tableView setEditing:YES animated:YES];即可进入编辑模式。然后实现下面的方法即可开启移动cell。
//默认编辑模式下,每个cell左边有个红色的删除按钮,设置为None即可去掉

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleNone;
}
//是否允许indexPath的cell移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    //更新数据源
}

用系统的方法有几个缺点:
1.需要用一个开关去控制编辑状态,不方便;
2.移动cell的时候cell右边有个指示图标,看着不爽;
3.被移动cell的样式不能自己定制。
综上所述,需要自己去写效果了。

实现原理
大概原理:为UITableView添加一个长按手势,然后给选中的cell截图;让截图随着手势移动,同时记录选中的indexPath,方便位置互换。

1.添加长按手势

longPressGesutre = UILongPressGestureRecognizer.init(target: self, action:#selector(HomePageViewController.handleLongpressGesture(_:)))
        longPressGesutre.minimumPressDuration = 0.5
        self.tableView.addGestureRecognizer(longPressGesutre)

2.处理手势开始

    func handleLongpressGesture(sender:UILongPressGestureRecognizer) {

        switch sender.state {
        case UIGestureRecognizerState.Began:
            gestureBegan(sender)
            break
        case UIGestureRecognizerState.Changed:
            gestureChanged(sender)
            break
        case UIGestureRecognizerState.Cancelled:
            gestureEnded(sender)
            break
        case UIGestureRecognizerState.Ended:
            gestureEnded(sender)
            break
        default:

            break
        }
    }

3 开始处理手势

private func gestureBegan(gesture:UILongPressGestureRecognizer) {
        let location:CGPoint = gesture.locationInView(self.tableView)
        let indexPath:NSIndexPath! = self.tableView.indexPathForRowAtPoint(location)

        if indexPath != nil {
            // 开启边缘滚动
            startEdgeScroll()
            sourceIndexPath = indexPath
            let cell:HomeSubTableViewCell = self.tableView.cellForRowAtIndexPath(indexPath) as! HomeSubTableViewCell
            snapshot = self.customSnapshotFromView(cell)
            var center:CGPoint = cell.center
            snapshot.center = center
            snapshot.alpha = 0
            self.tableView.addSubview(snapshot)
            UIView.animateWithDuration(0.25, animations: {
                center.y = location.y
                self.snapshot.center = center
                self.snapshot.transform = CGAffineTransformMakeScale(1, 1)
                self.snapshot.alpha = 1.0
                self.snapshotColor = cell.backgroundColor
                cell.backgroundColor = UIColor.clearColor()
                cell.hidden = true
                }, completion: nil)
        }
    }

4 处理手势状态变化,并交换数据源

private func gestureChanged(gesture:UILongPressGestureRecognizer) {
        let location:CGPoint = gesture.locationInView(self.tableView)
        let indexPath:NSIndexPath! = self.tableView.indexPathForRowAtPoint(location)
        var center:CGPoint = snapshot.center
        center.y = location.y
        snapshot.center = center
        if indexPath != nil && indexPath.isEqual(sourceIndexPath) == false {

            let cellA:HomeSubTableViewCell = tableView.cellForRowAtIndexPath(sourceIndexPath) as! HomeSubTableViewCell
            let cellB:HomeSubTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as! HomeSubTableViewCell
            let modelToMove:HomePageCellModel = self.dataArr![sourceIndexPath.row]
            self.dataArr!.removeAtIndex(sourceIndexPath.row)
            self.dataArr!.insert(modelToMove, atIndex: indexPath.row)
            StoreDataModel.sharedInstance.changeChooseRate((cellA.model?.nameEn)!, codeB: (cellB.model?.nameEn)!)
            self.tableView.moveRowAtIndexPath(sourceIndexPath, toIndexPath: indexPath)
            sourceIndexPath = indexPath
        }
    }

5 手势结束或者取消,结束之后将视图还原

private func gestureEnded(gesture:UILongPressGestureRecognizer) {
        if edgeScrollTimer != nil {
            edgeScrollTimer.invalidate()
            edgeScrollTimer = nil
        }
        let cell:HomeSubTableViewCell = self.tableView.cellForRowAtIndexPath(sourceIndexPath) as! HomeSubTableViewCell
        UIView.animateWithDuration(0.25, animations: {
            self.snapshot.center = cell.center
            self.snapshot.transform = CGAffineTransformIdentity
            self.snapshot.alpha = 0
            cell.backgroundColor = self.snapshotColor
            cell.hidden = false
            }, completion: { (finished:Bool) in
                self.snapshot.removeFromSuperview()
                self.snapshot = nil
        })
        sourceIndexPath = nil
    }

6.处理边缘滚动

///开始边界翻滚
    private func startEdgeScroll() {
        edgeScrollTimer = CADisplayLink.init(target: self, selector: #selector(processEdgeScroll))
        edgeScrollTimer.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
    }

    @objc private func processEdgeScroll() {

        gestureChanged(longPressGesutre)

        let minOffsetY:CGFloat = self.tableView.contentOffset.y + 150
        let maxOffsetY:CGFloat = self.tableView.contentOffset.y + self.tableView.bounds.size.height - 150
        let touchPoint = snapshot.center

        //处理上下达到极限之后不再滚动tableView,其中处理了滚动到最边缘的时候,当前处于edgeScrollRange内,但是tableView还未显示完,需要显示完tableView才停止滚动
        if touchPoint.y < 150 {
            if self.tableView.contentOffset.y <= 0 {
                return
            } else {
                if self.tableView.contentOffset.y - 1 < 0 {
                    return;
                }
                self.tableView.setContentOffset(CGPointMake(self.tableView.contentOffset.x
                    , self.tableView.contentOffset.y), animated: false)
                snapshot.center = CGPointMake(snapshot.center.x, snapshot.center.y - 1)
            }

        }

        if touchPoint.y > self.tableView.contentSize.height - 150 {
            if self.tableView.contentOffset.y >= self.tableView.contentSize.height - self.tableView.bounds.size.height {
                return
            } else {
                if self.tableView.contentOffset.y + 1 > self.tableView.contentSize.height - self.tableView.bounds.size.height {
                    return;
                }
                self.tableView.setContentOffset(CGPointMake(self.tableView.contentOffset.x, self.tableView.contentOffset.y + 1), animated: false)
                snapshot.center = CGPointMake(snapshot.center.x, snapshot.center.y + 1)
            }
        }
        // 处理滚动
        let maxMoveDistance:CGFloat = 20

        if touchPoint.y < minOffsetY {
            // cell在向上滚动
            let moveDistance:CGFloat = (minOffsetY - touchPoint.y) / 150 * maxMoveDistance
            self.tableView.setContentOffset(CGPointMake(self.tableView.contentOffset.x, self.tableView.contentOffset.y - moveDistance), animated: false)
            snapshot.center = CGPointMake(snapshot.center.x, snapshot.center.y - moveDistance)
        } else if touchPoint.y > maxOffsetY {
            // cell在向下滚动
            let moveDistance:CGFloat = (touchPoint.y - maxOffsetY) / 150 * maxMoveDistance
            self.tableView.setContentOffset(CGPointMake(self.tableView.contentOffset.x, self.tableView.contentOffset.y + moveDistance), animated: false)
            snapshot.center = CGPointMake(snapshot.center.x, snapshot.center.y + moveDistance)
        }
    }

总结
通过截图实现以假乱真,自由移动截图产生的”cell”;交换的时候,首先要交换数据源,再交换cell;处理边缘滚动的时候,需要小心各种边界条件。

版权声明:阳仔原创,转载请注明出处。

iOS_UITableView 编辑(cell的插入, 删除, 移动)

iOS_UITableView 编辑(cell的插入, 删除, 移动) 说明: UITableView 中的cell的插入, 删除, 移动效果的实现, 主要通过UITableView的协议中...
  • Sponge_CMZ
  • Sponge_CMZ
  • 2015年08月14日 10:09
  • 4720

iOS UITableView(四)-Cell拖动更改排序

本文主要内容: 1. UITableview更改cell顺序; 2.UITableview的一些小细节。1.更改cell顺序效果图: 实现方式:1.创建一个数组,存放UITableView的数据...
  • u013892686
  • u013892686
  • 2016年07月18日 16:31
  • 4791

iOS自定义长按手势,随意拖动Cell

iOS自定义长按手势,随意拖动Cell起因 最近在做一个项目,要对UITableViewCell进行拖动蹂躏,具体效果如下: 本来打算用UIRespon这几个方法来做,最后发现在UITableView...
  • u012399689
  • u012399689
  • 2015年04月29日 19:32
  • 4408

iOS TableView 自带可拖动重排功能

使用UITableView 自带的各种风格对tableView进行动态的添加,删除,重排
  • u013352096
  • u013352096
  • 2016年03月23日 16:14
  • 3520

iOS-TableView拖动Cell更换次序

效果: 长按某个Cell,Cell会有一个明显的弹起放大效果。这时候,你可以通过拖动cell和其他Cell更换顺序。   实现的原理: 1,浮层 长按后,UITa...
  • sadsadaadsd
  • sadsadaadsd
  • 2016年12月04日 10:31
  • 1548

iOS之实现按钮拖动/tableViewcell多选,拖动/collectionviewcell多选,拖动(交换位置)

iOS之实现按钮拖动
  • u011146511
  • u011146511
  • 2017年04月18日 23:23
  • 400

IOS UITableView 改变编辑模式下的移动图标

IOS UITableView改变编辑模式下的移动图标
  • android_wxl
  • android_wxl
  • 2016年05月16日 14:57
  • 1292

IPhone 自定义 UITableViewCell 行缩进,使cell进入编辑状态时不右移

IPhone 自定义 UITableViewCell 行缩进 在cell.m中重写setEditing: animated:以使cell进入编辑状态时不右移 转自至:http://ww...
  • YLGWHYH
  • YLGWHYH
  • 2016年07月12日 22:32
  • 3742

iOS开发——纯代码界面(自定义UITableViewCell)

自定义UITableViewCell创建一个TableViewController类继承于UITableViewController,创建一个TableViewCell类继承于UITableViewC...
  • u012350430
  • u012350430
  • 2016年04月18日 18:25
  • 11136

iOS纯代码自定义UITableViewCell及性能优化

知识准备      自定义Cell的实现方式         1. 纯代码方式:纯代码又可以通过frame和autolayout技术来实现         2.XIB方式         3.Stor...
  • vbirdbest
  • vbirdbest
  • 2016年08月25日 14:15
  • 2758
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:iOS - 移动自定义UITableViewCell
举报原因:
原因补充:

(最多只允许输入30个字)