gridview拖拽排序

可自由设置不能拖拽的位置,选中的位置,及拖拽的镜像样式
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Vibrator;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import com.dealmoon.android.R;
import com.north.expressnews.home.TextViewAdapter;

public class DragGridViewItemLine extends GridView {
    /**
     * DragGridViewitem长按响应的时间, 默认是1000毫秒,也可以自行设置
     */
    private long dragResponseMS = 1000;

    /**
     * 是否可以拖拽,默认不可以
     */
    private boolean isDrag = false;

    /**
     * 功能设置:是否能拖拽
     */
    private boolean dragEnable = true;

    /**
     * 设置不能拖动的位置
     * 忽略的位置,用于长按此类位置不进行移动
     */
    private int[] ignorePositions;

    private int mDownX;
    private int mDownY;
    private int moveX;
    private int moveY;
    /**
     * 正在拖拽的position
     */
    private int mDragPosition;

    /**
     * 刚开始拖拽的item对应的View
     */
    private View mStartDragItemView = null;

    /**
     * 用于拖拽的镜像,这里直接用一个ImageView
     */
    private ImageView mDragImageView;

    /**
     * 震动器
     */
    private Vibrator mVibrator;

    private WindowManager mWindowManager;
    /**
     * item镜像的布局参数
     */
    private WindowManager.LayoutParams mWindowLayoutParams;

    /**
     * 我们拖拽的item对应的Bitmap
     */
    private Bitmap mDragBitmap;

    /**
     * 按下的点到所在item的上边缘的距离
     */
    private int mPoint2ItemTop;

    /**
     * 按下的点到所在item的左边缘的距离
     */
    private int mPoint2ItemLeft;

    /**
     * DragGridView距离屏幕顶部的偏移量
     */
    private int mOffset2Top;

    /**
     * DragGridView距离屏幕左边的偏移量
     */
    private int mOffset2Left;

    /**
     * 状态栏的高度
     */
    private int mStatusHeight;

    /**
     * DragGridView自动向下滚动的边界值
     */
    private int mDownScrollBorder;

    /**
     * DragGridView自动向上滚动的边界值
     */
    private int mUpScrollBorder;

    /**
     * DragGridView自动滚动的速度
     */
    private static final int speed = 20;

    private boolean isNeedItemBorder = true;

    private int mDragItemBackground = 0;

    public void setNeedItemBorder(boolean needItemBorder) {
        isNeedItemBorder = needItemBorder;
    }

    public void setDragItemBackground(int bg) {
        mDragItemBackground = bg;
    }

    /**
     * item发生变化回调的接口
     */
    private OnChanageListener onChanageListener;

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

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

    public DragGridViewItemLine(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mVibrator = (Vibrator) context
                .getSystemService(Context.VIBRATOR_SERVICE);
        mWindowManager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        mStatusHeight = getStatusHeight(context); // 获取状态栏的高度

    }

    public void setDragEnable(boolean enable) {
        dragEnable = enable;
    }

    /**
     * 设置不能拖动的位置
     * 忽略的位置,用于长按此类位置不进行移动
     */
    public void setIgnoreDragPosition(@NonNull int[] ignorePositions) {
        this.ignorePositions = ignorePositions;
    }


    private boolean checkIsIgnoreDragPosition(int dragPosition) {
        if (ignorePositions != null) {
            for (int i = 0, j = ignorePositions.length; i < j; i++) {
                if (dragPosition == ignorePositions[i]) {
                    return true;
                }
            }
        }
        return false;
    }
    

    private Handler mHandler = new Handler();

    // 用来处理是否为长按的Runnable
    private Runnable mLongClickRunnable = new Runnable() {

        @Override
        public void run() {
            isDrag = true; // 设置可以拖拽
            mVibrator.vibrate(50); // 震动一下

            ColorStateList colorStateList = setTextColor(mStartDragItemView, getContext().getResources().getColor(R.color.white));
            // 开启mDragItemView绘图缓存
            mStartDragItemView.setDrawingCacheEnabled(true);
            // 缓存背景色
            if (mDragItemBackground != 0) {
                mStartDragItemView.setBackgroundResource(mDragItemBackground);
                mStartDragItemView.setDrawingCacheBackgroundColor(Color.TRANSPARENT);
            } else {
                mStartDragItemView.setDrawingCacheBackgroundColor(getContext().getResources().getColor(R.color.dm_main));
            }
            // 获取mDragItemView在缓存中的Bitmap对象
            mDragBitmap = Bitmap.createBitmap(mStartDragItemView
                    .getDrawingCache());
            // 这一步很关键,释放绘图缓存,避免出现重复的镜像
            mStartDragItemView.destroyDrawingCache();

            setTextColor(mStartDragItemView, colorStateList);
            
            mStartDragItemView.setVisibility(View.INVISIBLE);// 隐藏该item

            // 根据我们按下的点显示item镜像
            createDragImage(mDragBitmap, mDownX, mDownY);
        }
    };


    private ColorStateList setTextColor(View parentView, int textColor) {
        ColorStateList colorStateList = null;
        System.out.println("setTextColor "+parentView.toString());
        if (parentView instanceof TextView) {
            colorStateList = ((TextView) parentView).getTextColors();

            ((TextView) parentView).setTextColor(textColor);
            parentView.invalidate();
        }
//        else if (parentView instanceof AbsListView) {
//            for (int i = 0, j = ((AbsListView) parentView).getChildCount(); i < j; i++) {
//                if (((AbsListView) parentView).getChildAt(i) instanceof TextView) {
//                    TextView tx = (TextView) ((AbsListView) parentView).getChildAt(i);
//
//                    colorStateList = tx.getTextColors();
//
//                    tx.setTextColor(textColor);
//                    tx.invalidate();
//                }
//
//            }
//        } 
        else if (parentView instanceof ViewGroup) {
            for (int i = 0, j = ((ViewGroup) parentView).getChildCount(); i < j; i++) {
                if (((ViewGroup) parentView).getChildAt(i) instanceof TextView) {
                    TextView tx = (TextView) ((ViewGroup) parentView).getChildAt(i);

                    colorStateList = tx.getTextColors();

                    tx.setTextColor(textColor);
                    tx.invalidate();
                }

            }
        }
        return colorStateList;
    }

    private void setTextColor(View parentView, ColorStateList colorStateList) {
        if (parentView instanceof TextView) {
            ((TextView) parentView).setTextColor(colorStateList);
            parentView.invalidate();
        }
//        else if (parentView instanceof AbsListView) {
//            for (int i = 0, j = ((AbsListView) parentView).getChildCount(); i < j; i++) {
//                if (((AbsListView) parentView).getChildAt(i) instanceof TextView) {
//                    TextView tx = (TextView) ((AbsListView) parentView).getChildAt(i);
//                    tx.setTextColor(colorStateList);
//                    tx.invalidate();
//                }
//
//            }
//        }
        else if (parentView instanceof ViewGroup) {
            for (int i = 0, j = ((ViewGroup) parentView).getChildCount(); i < j; i++) {
                if (((ViewGroup) parentView).getChildAt(i) instanceof TextView) {
                    TextView tx = (TextView) ((ViewGroup) parentView).getChildAt(i);
                    tx.setTextColor(colorStateList);
                    tx.invalidate();
                }

            }
        }
    }
    
    
    
    
    /**
     * 设置回调接口
     *
     * @param onChanageListener
     */
    public void setOnChangeListener(OnChanageListener onChanageListener) {
        this.onChanageListener = onChanageListener;
    }

    /**
     * 设置响应拖拽的毫秒数,默认是1000毫秒
     *
     * @param dragResponseMS
     */
    public void setDragResponseMS(long dragResponseMS) {
        this.dragResponseMS = dragResponseMS;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (isNeedItemBorder) {
            View localView1 = getChildAt(0);
            int column = getWidth() / localView1.getWidth();
            int childCount = getChildCount();
            Paint localPaint;
            localPaint = new Paint();
            localPaint.setStyle(Paint.Style.STROKE);
            localPaint.setColor(getContext().getResources().getColor(R.color.dm_line));
            for (int i = 0; i < childCount; i++) {
                View cellView = getChildAt(i);
                if ((i + 1) % column == 0) {
                    canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
                } else if ((i + 1) > (childCount - (childCount % column))) {
                    canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
                } else {
                    canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
                    canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
                }
            }
            if (childCount % column != 0) {
                for (int j = 0; j < (column - childCount % column); j++) {
                    View lastView = getChildAt(childCount - 1);
                    canvas.drawLine(lastView.getRight() + lastView.getWidth() * j, lastView.getTop(), lastView.getRight() + lastView.getWidth() * j, lastView.getBottom(), localPaint);
                }
            }
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (!dragEnable) {
            return super.dispatchTouchEvent(ev);
        }

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:
                mDownX = (int) ev.getX();
                mDownY = (int) ev.getY();
                mDragPosition = pointToPosition(mDownX, mDownY);
                Log.i("+++++++itempos++++++", mDragPosition + "----"
                        + getAdapter().getCount());

                if (mDragPosition == 0 || mDragPosition == AdapterView.INVALID_POSITION) {

                    return super.dispatchTouchEvent(ev);
                }

                if (checkIsIgnoreDragPosition(mDragPosition)) {
                    return super.dispatchTouchEvent(ev);
                }
                

                if (getParent() != null) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                
                
                if (mDragPosition < getAdapter().getCount()) {
                    // 使用Handler延迟dragResponseMS执行mLongClickRunnable

                    mHandler.postDelayed(mLongClickRunnable, dragResponseMS);

                }

                // 根据position获取该item所对应的View
                mStartDragItemView = getChildAt(mDragPosition
                        - getFirstVisiblePosition());
              
                // 下面这几个距离大家可以参考我的博客上面的图来理解下
                mPoint2ItemTop = mDownY - mStartDragItemView.getTop();
                mPoint2ItemLeft = mDownX - mStartDragItemView.getLeft();

                mOffset2Top = (int) (ev.getRawY() - mDownY);
                mOffset2Left = (int) (ev.getRawX() - mDownX);

                // 获取DragGridView自动向上滚动的偏移量,小于这个值,DragGridView向下滚动
                mDownScrollBorder = getHeight() / 4;
                // 获取DragGridView自动向下滚动的偏移量,大于这个值,DragGridView向上滚动
                mUpScrollBorder = getHeight() * 3 / 4;

//                // 开启mDragItemView绘图缓存
//                mStartDragItemView.setDrawingCacheEnabled(true);
//                // 缓存背景色
//                mStartDragItemView.setDrawingCacheBackgroundColor(Color.parseColor("#FFFFFF00"));
//                // 获取mDragItemView在缓存中的Bitmap对象
//                mDragBitmap = Bitmap.createBitmap(mStartDragItemView
//                        .getDrawingCache());
//                // 这一步很关键,释放绘图缓存,避免出现重复的镜像
//                mStartDragItemView.destroyDrawingCache();

                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();
                int moveY = (int) ev.getY();

                if (getParent() != null) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                
                // 如果我们在按下的item上面移动,只要不超过item的边界我们就不移除mRunnable
                if (!isTouchInItem(mStartDragItemView, moveX, moveY)) {
                    mHandler.removeCallbacks(mLongClickRunnable);
                }
                break;
            case MotionEvent.ACTION_UP:
                int moveXup = (int) ev.getX();
                int moveYup = (int) ev.getY();
                // if (Math.abs(moveXup - mDownX) < 5 && Math.abs(moveYup - mDownY)
                // < 5) {
                // isDrag = true;
                // } else {
                // isDrag = false;
                // }
                
                if (getParent() != null) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                
                mHandler.removeCallbacks(mLongClickRunnable);
                mHandler.removeCallbacks(mScrollRunnable);
                break;
        }
        super.dispatchTouchEvent(ev);

        // Log.i("+++++++ACTION_UP++++++", "+++++++ACTION_UP++++++" +longclick
        // );

        return super.dispatchTouchEvent(ev);
    }

    /**
     * 是否点击在GridViewitem上面
     *
     * @param dragView
     * @param x
     * @param y
     * @return
     */
    private boolean isTouchInItem(View dragView, int x, int y) {
        if (dragView == null) {
            return false;
        }
        int leftOffset = dragView.getLeft();
        int topOffset = dragView.getTop();
        if (x < leftOffset || x > leftOffset + dragView.getWidth()) {
            return false;
        }

        if (y < topOffset || y > topOffset + dragView.getHeight()) {
            return false;
        }

        return true;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!dragEnable) {
            return super.onTouchEvent(ev);
        }

        if (isDrag && mDragImageView != null) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    moveX = (int) ev.getX();
                    moveY = (int) ev.getY();
                    // 拖动item
                    onDragItem(moveX, moveY);
                    break;
                case MotionEvent.ACTION_UP:
                    onStopDrag();
                    isDrag = false;
                    break;
            }
            return true;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 创建拖动的镜像
     *
     * @param bitmap
     * @param downX  按下的点相对父控件的X坐标
     * @param downY  按下的点相对父控件的X坐标
     */
    private void createDragImage(Bitmap bitmap, int downX, int downY) {
        mWindowLayoutParams = new WindowManager.LayoutParams();
//    mWindowLayoutParams.format = PixelFormat.TRANSLUCENT; // 图片之外的其他地方透明
        mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
        mWindowLayoutParams.x = downX - mPoint2ItemLeft + mOffset2Left;
        mWindowLayoutParams.y = downY - mPoint2ItemTop + mOffset2Top
                - mStatusHeight;
//    mWindowLayoutParams.alpha = 0.55f; // 透明度
        mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        mDragImageView = new ImageView(getContext());
        mDragImageView.setImageBitmap(bitmap);
        mWindowManager.addView(mDragImageView, mWindowLayoutParams);
    }

    /**
     * 从界面上面移动拖动镜像
     */
    private void removeDragImage() {
        if (mDragImageView != null) {
            mWindowManager.removeView(mDragImageView);
            mDragImageView = null;
        }
    }

    /**
     * 拖动item,在里面实现了item镜像的位置更新,item的相互交换以及GridView的自行滚动
     *
     * @param moveX
     * @param moveY
     */
    private void onDragItem(int moveX, int moveY) {
            mWindowLayoutParams.x = moveX - mPoint2ItemLeft + mOffset2Left;
            mWindowLayoutParams.y = moveY - mPoint2ItemTop + mOffset2Top
                    - mStatusHeight;
            mWindowManager.updateViewLayout(mDragImageView, mWindowLayoutParams); // 更新镜像的位置
            onSwapItem(moveX, moveY);

            // GridView自动滚动
            mHandler.post(mScrollRunnable);
//        }
      
    }

    /**
     * moveY的值大于向上滚动的边界值,触发GridView自动向上滚动 当moveY的值小于向下滚动的边界值,触犯GridView自动向下滚动
     * 否则不进行滚动
     */
    private Runnable mScrollRunnable = new Runnable() {

        @Override
        public void run() {
            int scrollY;
            if (getFirstVisiblePosition() == 0
                    || getLastVisiblePosition() == getCount() - 1) {
                mHandler.removeCallbacks(mScrollRunnable);
            }
            if (moveY > mUpScrollBorder) {
                scrollY = speed;
                mHandler.postDelayed(mScrollRunnable, 25);
            } else if (moveY < mDownScrollBorder) {
                scrollY = -speed;
                mHandler.postDelayed(mScrollRunnable, 25);
            } else {
                scrollY = 0;
                mHandler.removeCallbacks(mScrollRunnable);
            }

            // 当我们的手指到达GridView向上或者向下滚动的偏移量的时候,可能我们手指没有移动,但是DragGridView在自动的滚动
            // 所以我们在这里调用下onSwapItem()方法来交换item
            onSwapItem(moveX, moveY);

            smoothScrollBy(scrollY, 10);
        }
    };

    /**
     * 交换item,并且控制item之间的显示与隐藏效果
     *
     * @param moveX
     * @param moveY
     */
    private void onSwapItem(int moveX, int moveY) {
        // 获取我们手指移动到的那个itemposition
        int tempPosition = pointToPosition(moveX, moveY);
        if(tempPosition == 0){
            return;
        }
        else 
        if (tempPosition < getAdapter().getCount()) {

            // 假如tempPosition 改变了并且tempPosition不等于-1,则进行交换
            if (tempPosition != mDragPosition
                    && tempPosition != AdapterView.INVALID_POSITION) {
                if (onChanageListener != null) {
                    onChanageListener.onChange(mDragPosition, tempPosition);
                }

                getChildAt(tempPosition - getFirstVisiblePosition())
                        .setVisibility(View.INVISIBLE);// 拖动到了新的item,新的item隐藏掉
                getChildAt(mDragPosition - getFirstVisiblePosition())
                        .setVisibility(View.VISIBLE);// 之前的item显示出来

                mDragPosition = tempPosition;
            }

        }
    }

    /**
     * 停止拖拽我们将之前隐藏的item显示出来,并将镜像移除
     */
    private void onStopDrag() {
        View view = getChildAt(mDragPosition - getFirstVisiblePosition());
        if (view != null) {
            view.setVisibility(View.VISIBLE);
        }

        if (this.getAdapter() instanceof OnHideItemListener) {
            ((OnHideItemListener) getAdapter()).onItemHide(-1);
        } 
        
        removeDragImage();
    }

    /**
     * 获取状态栏的高度
     *
     * @param context
     * @return
     */
    private static int getStatusHeight(Context context) {
        int statusHeight = 0;
        Rect localRect = new Rect();
        ((Activity) context).getWindow().getDecorView()
                .getWindowVisibleDisplayFrame(localRect);
        statusHeight = localRect.top;
        if (0 == statusHeight) {
            Class<?> localClass;
            try {
                localClass = Class.forName("com.android.internal.R$dimen");
                Object localObject = localClass.newInstance();
                int i5 = Integer.parseInt(localClass
                        .getField("status_bar_height").get(localObject)
                        .toString());
                statusHeight = context.getResources().getDimensionPixelSize(i5);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return statusHeight;
    }

    /**
     * @author xiaanming
     */
    public interface OnChanageListener {

        /**
         * item交换位置的时候回调的方法,我们只需要在该方法中实现数据的交换即可
         *
         * @param form 开始的position
         * @param to   拖拽到的position
         */
        public void onChange(int form, int to);
    }


    /**
     * hide item
     * <p>
     * Created by hl on 2017/4/10.
     */
    public interface OnHideItemListener {
        public void onItemHide(int position);
    }
    
    
}

猜你喜欢

转载自blog.csdn.net/csdnwr/article/details/79359544
今日推荐