ListView的拖动和侧滑实现

本文详细介绍了在Android中实现ListView的拖动和侧滑删除功能。通过Android的Drag&Drop框架、WindowManager以及ViewDragHelper,分别解决拖动过程中控制拖动阴影、自定义拖动行为和实现侧滑删除的问题。并展示了每种实现方式的效果图。
摘要由CSDN通过智能技术生成

前言

ListView在Android App中占有重要的地位,很多界面的展示都要借助于这个控件,虽然RecyclerView已经逐步取代它的地位,掌握它的一些基本使用技巧还是很有必要的,现在就来探究一下如何实现拖动ListView的条目和侧滑删除ListView中的数据。

Android DND实现拖动

Android从3.0引入的Drag&Drop框架,实现在界面中的拖拽效果,用户为需要拖拽的子视图设置传递的数据、拖拽产生的阴影对象和本地数据等参数,调用View.startDrag方法就可以拖动子视图。同时还要对需要接收拖动事件的子视图设置拖动回调函数,拖动回调方法里处理多种拖动事件,根据拖动事件做出反应。

拖动事件 意义
DragEvent.ACTION_DRAG_STARTED 目标对象接收到拖动子视图开始,这时如果返回true代表对拖动的子视图感兴趣,系统会将后续的事件返送过来,否则就是不感兴趣,系统就忽略当前拖拽监视者,只会回调一次
DragEvent.ACTION_DRAG_ENTERED DRAG_STARTED返回true之后,拖动子视图进入当前监控子视图范围,只会回调一次
DragEvent.ACTION_DRAG_LOCATION 拖动子视图进入后开始准备向监控子视图drop,目前还在不断移动定位中,可以回调多次
DragEvent.ACTION_DRAG_EXITED 拖动子视图离开了当前监控子视图的范围,只会回调一次
DragEvent.ACTION_DROP 用户将拖动的子视图drop到当前监控子视图,只会回调一次
DragEvent.ACTION_DRAG_ENDED 用户松手后所有的其他事件都已发送处理完成,最后发送DRAG_ENDED事件

在ListView的拖动事件中,被拖动的子视图就是用户点击的子视图,监听的子视图是当前屏幕中所有的ListView展示的子视图,当然被拖动的子视图自己除外。通常的拖动操作都是经过LongClick触发,只需要在ListView的adapter中getView生成的View设置LongClick时间监听。

final View dragView = convertView;
convertView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        // DND框架要求传递的数据
        ClipData.Item item = new ClipData.Item(String.valueOf(position));
        ClipData clipData = new ClipData("", new String[] {
                ClipDescription.MIMETYPE_TEXT_PLAIN
        }, item);

        // 开始当前View的拖动操作,将当前拖动对象的position当作localState传递到拖动事件中
        dragView.startDrag(clipData, new View.DragShadowBuilder(dragView), position, 0);
        return true;
    }
});

View.DragShadowBuilder对象会在当前的界面上绘制子视图的外形称作DragShadow,也就是拖动阴影对象,这个对象会被透明化,这个应该是底层操作的,无法在应用层修改。设置了拖动监听之后开始设置其他的可能和它交换的Drag监听事件。

 convertView.setOnDragListener(new View.OnDragListener() {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                Log.d(TAG, "target: action = ACTION_DRAG_STARTED, clipData = " + event.getClipData());
                // 如果传递的数据类型正确,而且监听对象不是当前拖动的对象
                // event.getLocalState()可以获取前面拖动对方放进去的localState的position
                if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) &&
                        Integer.parseInt(String.valueOf(event.getLocalState())) != position) {
                    return true;
                }
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                Log.d(TAG, "target: action = ACTION_DRAG_ENTERED, clipData = " + event.getClipData());
               // 当进入当前监听对象,设置当前监听对象背景变色 dragView.setBackgroundColor(context.getResources().getColor(R.color.colorAccent));
                return true;
            case DragEvent.ACTION_DRAG_LOCATION:
                // 正在当前监听对象内拖动,不必关心
                Log.d(TAG, "target: action = ACTION_DRAG_LOCATION, clipData = " + event.getClipData());
                return true;
            case DragEvent.ACTION_DRAG_EXITED:
                // 如果离开了当前监听对象那么恢复当前监听对象的背景色
                Log.d(TAG, "target: action = ACTION_DRAG_EXITED, clipData = " + event.getClipData());
     dragView.setBackgroundColor(Color.WHITE);
                return true;
            case DragEvent.ACTION_DROP:
                Log.d(TAG, "target: action = ACTION_DROP, clipData = " + event.getClipData());
                final int srcPosition = Integer.parseInt((String) event.getClipData().getItemAt(0).getText());
                // 如果用户将拖动对象drop到了当前监听对象,
               // 交换拖动对象和当前监听对象数据位置并且刷新
                if (srcPosition == position) {
                    return true;
                }
                Collections.swap(users, srcPosition, position);
                notifyDataSetChanged();
                return <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值