Android实现可拖拽的GridView效果长按可拖拽删除数据源
作者:Leafact 发布时间:2022-10-22 17:39:32
标签:android,gridview,拖拽,删除
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效果长按可拖拽删除数据源网站的支持!
来源:http://blog.csdn.net/leafact/article/details/49178475


猜你喜欢
- 不同的加锁顺序我们来看一个不同加锁顺序的例子:public class DiffLockOrder {private int amount;
- 自定义类:using System;using System.Collections.Generic;using System.Linq;u
- 一、前言随着互联网项目前后端分离方式的流行,前端与后端交给不同的人员开发,项目沟通成本也随之提高。主要表现在WebAPI接口的沟通,Swag
- 一、做一个小测试通过注释,标注出下面两个类中每个方法的执行顺序,并写出studentId的最终值。package com.nezha.jav
- 通过这篇文章通过实例代码向大家介绍了Spring实例化bean的几种方法,接下来看看具体内容吧。1.使用类构造器实现实例化(bean的自身构
- 前言本篇我们就来讲讲Fragment管理中的 Add() 方法Add()在我们动态的添加、管理Fragment中,Add属于最基础的方法了;
- 一:大小比较:使用 String.compareTo 方法compareTo() 的返回值是int, 它是先比较对应字符的大小(ASCII码
- 前言相信很多人对枚举并不陌生,枚举可以很方便和直观的管理一组特定值。如果我们在页面上直接输出我们希望匹配的汉语意思或则其他满足我们需求的语句
- 本文汇总了C#启动外部程序的几种常用方法,非常具有实用价值,主要包括如下几种方法:1. 启动外部程序,不等待其退出。2. 启动外部程序,等待
- 前言以下为本文要记录的大概内容:Java基础案例:两只老虎、三个和尚、考试奖励以下是本篇文章正文内容,仅供参考一、案例1:两只老虎1.题目:
- 在项目开发中,我们经常需要进行动态添加组件,其中可添加的部分有两项:布局和组件 其中,添加的布局主要有RelativeLayout
- 本文实例讲述了Android编程之动态壁纸。分享给大家供大家参考,具体如下:从android 2.1版本起引入了动态壁纸的概念,熟悉andr
- 本文实例讲述了Android返回键功能的实现方法。分享给大家供大家参考。具体如下:在开发android应用时,常常通过按返回键(即keyCo
- 这篇文章主要介绍了java读取xml配置参数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友
- 什么是Aop主要介绍springboot中aop的使用,用过Spring框架的都知道,aop是spring框架的两大核心功能之一,还有一个就
- 本文实例总结了Android开发中Toast显示消息的方法。分享给大家供大家参考,具体如下:Android中提供一种简单的Toast消息提示
- springboot+调用支付宝第三方接口(沙箱环境)大神勿喷!!网址:https://developers.alipay.com/plat
- 值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容
- 1:@Qualifier@Qualifier 注释指定注入 Bean 的名称,这样歧义就消除了。所以@Auto
- 今天记录一下TextView的倒影效果,显示一串文字,然后在文字的下方显示出它的倒影,先上效果图:最重要的就是View中getDrawing