Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换

简单修改,完成自己想要的功能:长按,移到垃圾桶,删除数据。

主要思路是:

1.获取到用户长按的操作

2.获取按下的图片的bitmap以及移动的时候动态刷新镜像

3 action_up的时候判断镜像的位置,进入是否删除逻辑

自定义控件

package com.leafact.GridView;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
/**
 * 长按能选中item的,丢入垃圾箱的gridView
 *
 * @author leafact
 *
 */
public class MoveGridView extends GridView {
  private WindowManager mWindowManager;
  /**
   * item镜像的布局参数
   */
  private WindowManager.LayoutParams mWindowLayoutParams;
  /**
   * 震动器
   */
  private Vibrator mVibrator;
  // 震动的时间,默认为100ms
  private long vibratorMs = 100;
  // 设置长按时间为1秒
  private long responseMS = 1000;
  private static boolean isMove = false;
  // 按下去的x,y
  private int mDownX = 0;
  private int mDownY = 0;
  // 移动的时候的x,y
  private int mMoveX = 0;
  private int mMoveY = 0;
  // 抬起的x,y
  private int mUpX = 0;
  private int mUpY = 0;
  private int mPoint2ItemTop;
  private int mPoint2ItemLeft;
  private int mOffset2Top;
  private int mOffset2Left;
  /**
   * 状态栏的高度
   */
  private int mStatusHeight;
  public MoveGridView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mVibrator = (Vibrator) context
        .getSystemService(Context.VIBRATOR_SERVICE);
    mWindowManager = (WindowManager) context
        .getSystemService(Context.WINDOW_SERVICE);
    mStatusHeight = getStatusHeight(context); // 获取状态栏的高度
  }
  // 要移动的item的位置,默认为INVALID_POSITION=-1
  private int mMovePosition = INVALID_POSITION;
  /**
   * 刚开始拖拽的item对应的View
   */
  private View mStartMoveItemView = null;
  private ImageView mMoveImageView = null;
  private Bitmap mMoveBitmap;
  private Handler mHandler = new Handler();
  // 判断是否能开始移动元素
  private Runnable mLongClickRunnable = new Runnable() {
    @Override
    public void run() {
      isMove = true;
      mVibrator.vibrate(vibratorMs);
      // 根据我们按下的点显示item镜像
      createDragImage(mMoveBitmap, mDownX, mDownY);
    }
  };
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
      mDownX = (int) ev.getX();
      mDownY = (int) ev.getY();
      System.out.println("ACTION_DOWN");
      // 根据按下的X,Y坐标获取所点击item的position
      mMovePosition = pointToPosition(mDownX, mDownY);
      // 如果选中的为非法的位置。则不处理消息
      if (mMovePosition == AdapterView.INVALID_POSITION) {
        break;
      }
      mHandler.postDelayed(mLongClickRunnable, responseMS);
      mStartMoveItemView = getChildAt(mMovePosition
          - getFirstVisiblePosition());
      mPoint2ItemTop = mDownY - mStartMoveItemView.getTop();
      mPoint2ItemLeft = mDownX - mStartMoveItemView.getLeft();
      mOffset2Top = (int) (ev.getRawY() - mDownY);
      mOffset2Left = (int) (ev.getRawX() - mDownX);
      // 开启mMoveItemView绘图缓存
      mStartMoveItemView.setDrawingCacheEnabled(true);
      // 获取mMoveItemView在缓存中的Bitmap对象
      mMoveBitmap = Bitmap.createBitmap(mStartMoveItemView
          .getDrawingCache());
      // 这一步很关键,释放绘图缓存,避免出现重复的镜像
      mStartMoveItemView.destroyDrawingCache();
      break;
    case MotionEvent.ACTION_MOVE:
      mMoveX = (int) ev.getX();
      mMoveY = (int) ev.getY();
      // 如果我们在按下的item上面移动,只要不超过item的边界我们就不移除mRunnable
      // 依然能监听到longClick
      if (!isTouchInItem(mStartMoveItemView, mMoveX, mMoveY)) {
        mHandler.removeCallbacks(mLongClickRunnable);
      }
      // //禁止Gridview侧边进行滑动,移动的时候不许发生侧滑事件
      if (isMove) {
        onDragItem(mMoveX, mMoveY);
        return true;
      }
      break;
    case MotionEvent.ACTION_UP:
      mUpX = (int) ev.getX();
      mUpY = (int) ev.getY();
      mHandler.removeCallbacks(mLongClickRunnable);
      if(isMove){
        deleteIfNeed();
      }
      removeDragImage();
      isMove = false;
      break;
    default:
      break;
    }
    return super.onTouchEvent(ev);
  }
  /**
   * 判断是否要删除,满足条件删除
   */
  private void deleteIfNeed() {
    int y = mUpY - mPoint2ItemTop + mOffset2Top
        - mStatusHeight;
    if(y<50){
      if(mUninstallListener!=null)
      mUninstallListener.onUninstallListener(mMovePosition);
    }
  }
  /**
   * 是否点击在GridView的item上面
   *
   * @param itemView
   * @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;
  }
  /**
   * 创建拖动的镜像
   *
   * @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;
    mMoveImageView = new ImageView(getContext());
    mMoveImageView.setImageBitmap(bitmap);
    mWindowManager.addView(mMoveImageView, mWindowLayoutParams);
  }
  /**
   * 从界面上面移动拖动镜像
   */
  private void removeDragImage() {
    if (mMoveImageView != null) {
      mWindowManager.removeView(mMoveImageView);
      mMoveImageView = null;
    }
  }
  /**
   * 拖动item,在里面实现了item镜像的位置更新,item的相互交换以及GridView的自行滚动
   *
   * @param x
   * @param y
   */
  private void onDragItem(int moveX, int moveY) {
    mWindowLayoutParams.x = moveX - mPoint2ItemLeft + mOffset2Left;
    mWindowLayoutParams.y = moveY - mPoint2ItemTop + mOffset2Top
        - mStatusHeight;
    mWindowManager.updateViewLayout(mMoveImageView, mWindowLayoutParams); // 更新镜像的位置
  }
  /**
   * 获取状态栏的高度
   *
   * @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;
  }
  /**
   * 设置响应拖拽的毫秒数,默认是1000毫秒
   *
   * @param responseMS
   */
  public void setResponseMS(long responseMS) {
    this.responseMS = responseMS;
  }
  /**
   * 设置震动时间的毫秒数,默认是1000毫秒
   *
   * @param responseMS
   */
  public void setVibrator(long vibratorMs) {
    this.vibratorMs = vibratorMs;
  }
  public void setOnUninstallListener(UninstallListener l){
    mUninstallListener=l;
  };
  private UninstallListener mUninstallListener;
} 

MainActivity.java

package com.example.gridviewmovedemo;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.SimpleAdapter;
import com.leafact.GridView.MoveGridView;
import com.leafact.GridView.UninstallListener;
public class MainActivity extends Activity {
  private MoveGridView mMoveGridView;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mMoveGridView = (MoveGridView) findViewById(R.id.gridview);
    final ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>();
    for (int i = 0; i < 10; i++) {
      HashMap<String, Object> map = new HashMap<String, Object>();
      map.put("ItemText", "NO." + String.valueOf(i));// 按序号做ItemText
      lstImageItem.add(map);
    }
    final SimpleAdapter saImageItems = new SimpleAdapter(this,
        lstImageItem,// 数据来源
        R.layout.gridview_item,
        // 动态数组与ImageItem对应的子项
        new String[] { "ItemText" },
        // ImageItem的XML文件里面的一个ImageView,两个TextView ID
        new int[] { R.id.ItemText });
    // 添加并且显示
    mMoveGridView.setAdapter(saImageItems);
    //监听到卸载删除数据
    mMoveGridView.setOnUninstallListener(new UninstallListener() {
      @Override
      public void onUninstallListener(int position) {
        lstImageItem.remove(position);
        saImageItems.notifyDataSetChanged();
      }
    });
  }
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }
} 

UninstallListener.java

package com.leafact.GridView;
public interface UninstallListener {
  void onUninstallListener(int position);
} 

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#fff"
  android:orientation="vertical"
  tools:context=".MainActivity" >
  <RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="100dip"
    android:background="#ccc" >
    <TextView
      android:layout_width="wrap_content"
      android:layout_height="fill_parent"
      android:layout_centerHorizontal="true"
      android:gravity="center"
      android:text="卸载"
      android:textColor="#fff"
      android:textSize="28sp" />
  </RelativeLayout>
  <com.leafact.GridView.MoveGridView
    android:id="@+id/gridview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:horizontalSpacing="5dip"
    android:numColumns="3"
    android:verticalSpacing="5dip" />
</LinearLayout> 

gridview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="#2248DD" >
  <TextView
    android:id="@+id/ItemText"
    android:layout_width="wrap_content"
    android:layout_height="100dip"
    android:layout_centerHorizontal="true"
    android:gravity="center" >
  </TextView>
</RelativeLayout> 

总结

以上所述是小编给大家介绍的Android实现可拖拽的GridView效果长按可拖拽删除数据源,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

01-31 05:40