当前位置: 首页 > article >正文

Android可长按拖拽item的列表

Android可长按拖拽item的列表

仿支付宝拖拽效果,长按拖拽item列表,自动换位

一、思路:

自定义控件DragGridView

二、效果图:

在这里插入图片描述
看视频更直观点:

Android轮子-可长按拖拽item的列表

三、关键代码:
package  com.cong.mydraglistapp.drag;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;


import com.cong.mydraglistapp.R;

import java.util.ArrayList;
import java.util.List;

import static android.widget.AdapterView.INVALID_POSITION;


public class DragGridView extends GridViewForScrollView {

    private static final int MOVE_DURATION = 300;
    private static final int SCROLL_SPEED = 60;
    private static final int EXTEND_LENGTH = 20;

    private Vibrator vibrator;
    private int lastX = -1;
    private int lastY = -1;

    /**
     * 拖动时的图像 和 它的位置
     */
    private BitmapDrawable hoverCell;
    private Rect currentRect;

    /**
     * 要拖动的view
     */
    private View selectView;
    private int originPosition = INVALID_POSITION;
    private int currentPosition = INVALID_POSITION;

    private boolean isEdit;
    public static boolean isDrag;
    private boolean isSwap;
    private List<Integer> noChangePositions = new ArrayList<>();

    Paint localPaint;//画笔
    Paint topPaint;//画笔

    private DragCallback dragCallback;

    public DragGridView(Context context) {
        this(context, null);
    }

    public DragGridView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);

        localPaint = new Paint();
        localPaint.setStrokeWidth(1);
        localPaint.setStyle(Paint.Style.STROKE);
        localPaint.setColor(getContext().getResources().getColor(R.color.c_f2f2f7));//设置画笔的颜色


        topPaint = new Paint();
        topPaint.setStrokeWidth(2);
        topPaint.setStyle(Paint.Style.STROKE);
        topPaint.setColor(getContext().getResources().getColor(R.color.c_f2f2f7));//设置画笔的颜色
    }

    public DragAdapterInterface getInterface() {
        return (DragAdapterInterface) getAdapter();
    }

    public void setDragCallback(DragCallback dragCallback) {
        this.dragCallback = dragCallback;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                if (isDrag) {
                    int offsetX = x - lastX;
                    int offsetY = y - lastY;

                    lastX = x;
                    lastY = y;

                    currentRect.offset(offsetX, offsetY);
                    if (hoverCell != null) {
                        hoverCell.setBounds(currentRect);
                    }
                    invalidate();
                    if (!isSwap) {
                        swapItems(x, y);
                    }
                    handleScroll();
                    return false;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (isDrag) {
                    endDrag();
                }
                break;
            default:
        }

        return super.onTouchEvent(ev);
    }

    public void clicked(int position) {
        if (isEdit) {
            isEdit = false;
            return;
        }
        // resumeView();
        Log.i("drag", "点击 Item " + position);
    }

    public List<Integer> getNoChangePositions() {
        return noChangePositions;
    }

    public void setNoChangePositions(List<Integer> noChangePositions) {
        this.noChangePositions = noChangePositions;
    }

    private void resumeView() {

        if (selectView != null) {
            // selectView.findViewById(R.id.delete_img).setVisibility(INVISIBLE);
            selectView.findViewById(R.id.item_container).setVisibility(VISIBLE);
            selectView.findViewById(R.id.item_container).setBackgroundColor(Color.WHITE);
        }
    }

    public void startDrag(int position) {
        if (position == INVALID_POSITION) {
            return;
        }
        // 恢复之前的图像,改变背景,去除删除按钮
        // resumeView();
        selectView = getChildAt(position - getFirstVisiblePosition());
        if (selectView != null) {
            isDrag = true;
            isEdit = true;

            /**
             * 移动的图像背景要有区别,并显示删除按钮
             */
            // selectView.findViewById(R.id.item_container).setBackgroundColor(Color.parseColor("#f0f0f0"));
//            if (selectView.findViewById(R.id.delete_img) != null) {
//                selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE);
//            }


            originPosition = position;
            currentPosition = position;

            // vibrator.vibrate(60); //震动

            // 获取图像
            hoverCell = getHoverCell(selectView);

            selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE);

            if (dragCallback != null) {
                dragCallback.startDrag(position);
            }

        }
    }

    private void swapItems(int x, int y) {
        int endPosition = pointToPosition(x, y);

        boolean canChange = true;
        for (int i:noChangePositions){
            if (endPosition == i){
                canChange = false;
                break;
            }
        }
        if (endPosition != INVALID_POSITION && endPosition != currentPosition && canChange) {
            isSwap = true;
            isEdit = false;
            resumeView();

            // 交换数据内容
            getInterface().reOrder(currentPosition, endPosition);

            selectView = getChildAt(endPosition - getFirstVisiblePosition());
            selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE);
            selectView.findViewById(R.id.item_container).setBackgroundColor(getContext().getResources().getColor(R.color.c_f2f2f7));
            //selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE);

            // 动画显示交换过程
            animateSwap(endPosition);

        }
    }

    private void animateSwap(int endPosition) {
        List<Animator> animators = new ArrayList<>();
        if (endPosition < currentPosition) {
            for (int i = endPosition + 1; i <= currentPosition; i++) {
                View view = getChildAt(i - getFirstVisiblePosition());
                if (i % getNumColumns() == 0) {
                    animators.add(createTranslationAnimations(view, view.getWidth() * (getNumColumns() - 1), 0,
                            -view.getHeight(), 0));
                } else {
                    animators.add(createTranslationAnimations(view, -view.getWidth(), 0, 0, 0));
                }
            }
        } else {
            for (int i = currentPosition; i < endPosition; i++) {
                View view = getChildAt(i - getFirstVisiblePosition());
                if ((i + 1) % getNumColumns() == 0) {
                    animators.add(createTranslationAnimations(view, -view.getWidth() * (getNumColumns() - 1), 0,
                            view.getHeight(), 0));
                } else {
                    animators.add(createTranslationAnimations(view, view.getWidth(), 0, 0, 0));
                }
            }
        }

        currentPosition = endPosition;

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animators);
        animatorSet.setDuration(MOVE_DURATION);
        animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isSwap = false;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animatorSet.start();
    }

    private Animator createTranslationAnimations(View view, float startX, float endX, float startY, float endY) {
        ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", startX, endX);
        ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY", startY, endY);
        AnimatorSet animSetXY = new AnimatorSet();
        animSetXY.playTogether(animX, animY);
        return animSetXY;
    }

    private void endDrag() {
        currentRect.set(selectView.getLeft(), selectView.getTop(), selectView.getRight(), selectView.getBottom());
        animateBound();
    }

    private void animateBound() {
        TypeEvaluator<Rect> evaluator = new TypeEvaluator<Rect>() {
            @Override
            public Rect evaluate(float fraction, Rect startValue, Rect endValue) {
                return new Rect(interpolate(startValue.left, endValue.left, fraction),
                        interpolate(startValue.top, endValue.top, fraction),
                        interpolate(startValue.right, endValue.right, fraction),
                        interpolate(startValue.bottom, endValue.bottom, fraction));
            }

            public int interpolate(int start, int end, float fraction) {
                return (int) (start + fraction * (end - start));
            }

        };

        ObjectAnimator animator = ObjectAnimator.ofObject(hoverCell, "bounds", evaluator, currentRect);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                invalidate();
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isDrag = false;

                if (currentPosition != originPosition) {
                    resumeView();
                    originPosition = currentPosition;
                }

                hoverCell = null;
                selectView.findViewById(R.id.item_container).setVisibility(VISIBLE);

                if (dragCallback != null) {
                    dragCallback.endDrag(currentPosition);
                }

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        animator.start();
    }

    private BitmapDrawable getHoverCell(View view) {
        int left = view.getLeft();
        int top = view.getTop();
        int w = view.getWidth();
        int h = view.getHeight();

        Bitmap bitmap = getBitmapFromView(view);
        BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
        currentRect = new Rect(left - EXTEND_LENGTH, top - EXTEND_LENGTH, left + w + EXTEND_LENGTH,
                top + h + EXTEND_LENGTH);

        drawable.setBounds(currentRect);
        return drawable;
    }

    private Bitmap getBitmapFromView(View v) {
        Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        v.draw(canvas);
        return bitmap;
    }

    private void handleScroll() {
        int offset = computeVerticalScrollOffset();
        int height = getHeight();
        int extent = computeVerticalScrollExtent();
        int range = computeHorizontalScrollRange();
        if (currentRect.top <= 0 && offset > 0) {
            smoothScrollBy(-SCROLL_SPEED, 0);
        } else if (currentRect.bottom >= height && (offset + extent) < range) {
            smoothScrollBy(SCROLL_SPEED, 0);
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (hoverCell != null) {
            hoverCell.draw(canvas);
        }

//        View localView1 = getChildAt(0);
//        int column = getWidth() / localView1.getWidth();//计算出一共有多少列,假设有3列
//        int childCount = getChildCount();//子view的总数
//        System.out.println("子view的总数childCount==" + childCount);
//
//        for (int i = 0; i < childCount; i++) {//遍历子view
//            View cellView = getChildAt(i);//获取子view
//            if (i < 4) {//第一行
//                canvas.drawLine(cellView.getLeft(), cellView.getTop(), cellView.getRight(), cellView.getTop(), topPaint);
//            }
//            if (i % column == 0) {//第一列
//                canvas.drawLine(cellView.getLeft(), cellView.getTop(), cellView.getLeft(), cellView.getBottom(), localPaint);
//            }
//            if ((i + 1) % column == 0) {//第三列
//                //画子view底部横线
//                canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
//                canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
//            } else if ((i + 1) > (childCount - (childCount % column))) {//如果view是最后一行
//                //画子view的右边竖线
//                canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
//                canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
//            } else {//如果view不是最后一行
//                //画子view的右边竖线
//                canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
//                //画子view的底部横线
//                canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
//            }
//        }
    }

//	@Override
//	public boolean onInterceptTouchEvent(MotionEvent ev) {
//		// TODO Auto-generated method stub
//		if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//			if (isDrag) {
//				return false;
//			} else {
//			}
//		}
//		return super.onInterceptTouchEvent(ev);
//	}

}

package com.cong.mydraglistapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;

import com.cong.mydraglistapp.drag.DragGridView;
import com.cong.mydraglistapp.drag.MyDragAdapter;

import java.util.ArrayList;
import java.util.List;

public class CatalogSortActivity extends AppCompatActivity {

    private DragGridView dragGridView;
    private MyDragAdapter adapterSelect;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_catalog_sort);

        dragGridView = findViewById(R.id.dgv_catalog);

        //模拟添加数据
        List<String> datas = new ArrayList<>();
        datas.add("A");
        datas.add("B");
        datas.add("C");
        datas.add("D");
        datas.add("E");
        datas.add("F");
        datas.add("G");
        datas.add("H");
        datas.add("I");
        datas.add("J");
        datas.add("K");
        datas.add("L");
        datas.add("N");
        datas.add("M");
        datas.add("O");
        datas.add("P");

        adapterSelect = new MyDragAdapter(this,datas);
        dragGridView.setAdapter(adapterSelect);

        dragGridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (!dragGridView.getNoChangePositions().contains(position)){
                    dragGridView.startDrag(position);
                }
                return false;
            }
        });
    }
}
四、项目demo源码效果图:

在这里插入图片描述
有问题或者需要完整demo源码的私信我,我每天都看私信的


http://www.kler.cn/a/430613.html

相关文章:

  • 【Redis】安装配置Redis超详细教程 / Linux版
  • Python网络自动化运维---批量登录设备
  • 【HTML入门】Sublime Text 4与 Phpstorm
  • AMD模块
  • 冷启动+强化学习:DeepSeek-R1 的原理详解——无需监督数据的推理能力进化之路
  • 基于WiFi的智能照明控制系统的设计与实现(论文+源码)
  • U2F和FIDO2 两种安全认证技术优劣势对比
  • 【万字详解】三维重建(二)——NeRF、NeuS、MeshUDF、NeuralUDF、3DGS、GShell
  • C语言单元总结
  • 虚幻引擎游戏开发专题-1-引擎术语
  • 关于转包关系和挂靠关系的认定
  • 【JavaEE初阶】CSS
  • 云贝教育【Oracle技术文章-Oracle 19c之PDB重命名】
  • 网络安全法 -网络信息安全
  • 深度学习的unfold操作
  • Flink WebUI解析(待更新)
  • 【iOS】UITextView
  • Ubuntu20.04调整swap分区大小笔记
  • 若依集成更好用的easyexcel
  • Freertos任务切换
  • P2440 木材加工(py)
  • 智能电网技术如何助力能源转型?
  • 暴⼒匹配算法和KMP算法介绍
  • 【实验15】LSTM的记忆能力实验
  • C++参数传递
  • 汽车总线协议分析-CAN总线