首页 > 其他分享 >Android可长按拖拽item的列表

Android可长按拖拽item的列表

时间:2024-12-11 09:30:00浏览次数:5  
标签:int private 可长 item import Android view public cellView

Android可长按拖拽item的列表

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

一、思路:

自定义控件DragGridView

二、效果图:

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

<iframe allowfullscreen="true" data-mediaembed="bilibili" frameborder="0" id="97szVlKF-1733794367531" src="https://player.bilibili.com/player.html?aid=976967428"></iframe>

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源码的私信我,我每天都看私信的

标签:int,private,可长,item,import,Android,view,public,cellView
From: https://blog.csdn.net/u010074743/article/details/144364423

相关文章

  • android 12 (1、屏幕旋转默认开启 (2、Font size 保持微 Largest 选项设置 (3、Font s
    —a/alps/frameworks/base/core/java/android/content/res/Configuration.java+++b/alps/frameworks/base/core/java/android/content/res/Configuration.java@@-1422,7+1422,7@@publicfinalclassConfigurationimplementsParcelable,Comparable<Configuration......
  • Android 13 源码编译
    前言全局说明一、说明1.1环境:Ubuntu18.04.6LTS(Linuxqt-vm5.4.0-150-generic#167~18.04.1-UbuntuSMPWedMay2400:51:42UTC2023x86_64x86_64x86_64GNU/Linux)1.2清华源AOSP清华源:https://mirrors.tuna.tsinghua.edu.cn/AOSP帮助:https://mirrors.tuna.tsi......
  • macOS 完全卸载 Android Studio 教程
    在macOS上,直接删除AndroidStudio应用后,许多配置文件和缓存可能仍会保留在系统中。为了彻底清除AndroidStudio,以下是完整的卸载步骤。1.删除AndroidStudio应用本体打开Finder,进入/Applications目录。找到AndroidStudio.app,然后将其拖动到废纸篓。清空废纸篓......
  • 【android】如何在Android head中获取Android.Content.Context对象
    在Android头部中获取Android.Content.Context对象,可以通过以下方法实现:通过Activity的getContext()方法获取Context对象:通过Activity的getContext()方法获取Context对象:通过View的getContext()方法获取Context对象:通过View的getContext()方法获取Context对象:通过Application......
  • Android笔记【20】利用Log来debug
    一、背景    在利用青云课API写聊天软件时,由于自己ui界面的column高度设计不当,导致没有看见下面的TextField,便没有输入信息,于是lazycolumn里面的messages.size为0,故不会显示内容。本人还以为无法运行到column内部,且在用text测试时由于两次text内容一致,在Box里面重叠,更......
  • .NET for Android/iOS如何调用jar、dylib和framework等包
    1.在.NETforAndroid中调用.jar文件(Java库)在.NETforAndroid中调用.jar文件,主要通过Xamarin.AndroidBindingLibrary来实现。.jar文件是Java库,通过绑定可以将Java方法映射为C#方法,以便在Xamarin.Android中调用。步骤:创建绑定库项目:创建一个JavaB......
  • Android记单词app(包含数据库)
    一、功能与要求 实现功能:设计与开发记单词系统的,系统功能包括用户登录、用户注册、单词操作(单词的添加、查询、修改及删除)以及忘记密码等。指标要求:通过用户登录、用户注册、单词操作、忘记密等功能的设计与开发,掌握Android常用布局、控件的使用、监听器的设置以及Android......
  • Camstar Modeling 报错 An item with the same key has already been added解决方案
     官方指导:(我们没用这个解决方案,可忽略阅读,直接看下面的)因为我们明细能看到,报错的位置,去反编译,查到错误的地方 打开desginer,查看这个查询语句 最后发现 selectobject_name(id)asname,rowsfromsysindexeswhereindid<2andobject_name(id)='hy_CheckByPN'......
  • 针尖对麦芒!Anthropic 推出 Claude Android 可实时翻译!
    Anthropic,作为OpenAI的强劲对手,于本周二正式推出了专为Android用户设计的Claude应用程序,旨在通过拓宽Claude的接入平台,吸引用户从ChatGPT转向其服务。这款Android应用承袭了五月问世的iOS版本的设计理念,用户无需支付任何费用即可体验到Anthropic顶尖AI模型——Claude3.5Sonnet的......
  • Android水波纹效果
    Android水波纹效果需要到水波纹效果的场景还蛮少的。万一刚好你需要呢一、思路:自定义组件SpreadView二、效果图:看视频更直观点:Android轮子分享-水波纹效果三、关键代码:publicclassSpreadViewextendsView{privatePaintcenterPaint;//中心圆paint......