Android学习系列(12)--App列表之拖拽GridView
根据前面文章中ListView拖拽的实现原理,我们也是很容易实现推拽GridView的,下面我就以相同步骤实现基本的GridView拖拽效果。
因为GridView不用做分组处理,代码处理起来更简洁,而且原理前面已经讲解清楚了,代码中只是简单的过下,必要的地方简单的注释一下。
1.主界面DragGridActivity.
6.
重写触控拦截事件方法onInterceptTouchEvent().
其中onDrag方法如下:
8.放下影像,数据更新。
在onDrop方法中实现:
因为GridView不用做分组处理,代码处理起来更简洁,而且原理前面已经讲解清楚了,代码中只是简单的过下,必要的地方简单的注释一下。
1.主界面DragGridActivity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class DragGridActivity extends Activity { private static List<String> list = null ; //自定义适配器 private DragGridAdapter adapter = null ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.drag_grid_activity); initData(); //后面用到的自定义GridView DragGridView dragGridView = (DragGridView)findViewById(R.id.drag_grid); adapter = new DragGridAdapter( this , list); dragGridView.setAdapter(adapter); } public void initData(){ //数据结果 list = new ArrayList<String>(); for ( int i= 0 ; i< 12 ; i++){ list.add( "grid_" +i% 12 ); } } } |
2.主界面UI布局drag_grid_activity.xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?xml version= "1.0" encoding= "utf-8" ?> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:orientation= "vertical" android:layout_width= "fill_parent" android:layout_height= "fill_parent" android:background= "#ffffff" android:padding= "10dip" > <com.fengjian.test.DragGridView android:id= "@+id/drag_grid" android:layout_width= "fill_parent" android:layout_height= "wrap_content" android:cacheColorHint= "#00000000" android:numColumns= "3" android:stretchMode= "columnWidth" android:verticalSpacing= "5dip" android:horizontalSpacing= "20dip" android:background= "#ffffff" /> </LinearLayout> |
3.列表项布局drag_grid_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:paddingLeft= "5dip" android:paddingRight= "5dip" > <ImageView android:id= "@+id/drag_grid_item_image" android:src= "@drawable/grid_icon" android:layout_margin= "5dip" android:layout_alignParentTop= "true" android:layout_width= "fill_parent" android:layout_height= "wrap_content" /> <ImageView android:id= "@+id/drag_grid_item_drag" android:src= "@drawable/grid_drag" android:layout_alignParentTop= "true" android:layout_alignParentRight= "true" android:layout_width= "wrap_content" android:layout_height= "wrap_content" /> </RelativeLayout> |
4.自定义适配器DragGridAdapter,继承ArrayAdapter<String>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public static class DragGridAdapter extends ArrayAdapter<String>{ public DragGridAdapter(Context context, List<String> objects) { super (context, 0 , objects); } public List<String> getList(){ return list; } @Override public View getView( int position, View convertView, ViewGroup parent) { View view = convertView; if (view== null ){ view = LayoutInflater.from(getContext()).inflate(R.layout.drag_grid_item, null ); } try { //根据文件名获取资源文件夹中的图片资源 Field f= (Field)R.drawable. class .getDeclaredField(getItem(position)); int i=f.getInt(R.drawable. class ); ImageView imageview= (ImageView)view.findViewById(R.id.drag_grid_item_image); imageview.setImageResource(i); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return view; } } |
5.自定义视图类DragGridView,继承GridView.
public class DragGridView extends GridView { //定义基本的成员变量 private ImageView dragImageView; private int dragSrcPosition; private int dragPosition; //x,y坐标的计算 private int dragPointX; private int dragPointY; private int dragOffsetX; private int dragOffsetY; private WindowManager windowManager; private WindowManager.LayoutParams windowParams; private int scaledTouchSlop; private int upScrollBounce; private int downScrollBounce; public DragGridView(Context context, AttributeSet attrs) { super (context, attrs); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction()==MotionEvent.ACTION_DOWN){ int x = ( int )ev.getX(); int y = ( int )ev.getY(); dragSrcPosition = dragPosition = pointToPosition(x, y); if (dragPosition==AdapterView.INVALID_POSITION){ return super .onInterceptTouchEvent(ev); } ViewGroup itemView = (ViewGroup) getChildAt(dragPosition-getFirstVisiblePosition()); dragPointX = x - itemView.getLeft(); dragPointY = y - itemView.getTop(); dragOffsetX = ( int ) (ev.getRawX() - x); dragOffsetY = ( int ) (ev.getRawY() - y); View dragger = itemView.findViewById(R.id.drag_grid_item_drag); //如果选中拖动图标 if (dragger!= null &&dragPointX>dragger.getLeft()&&dragPointX<dragger.getRight()&&dragPointY>dragger.getTop()&&dragPointY<dragger.getBottom()+ 20 ){ upScrollBounce = Math.min(y-scaledTouchSlop, getHeight()/ 4 ); downScrollBounce = Math.max(y+scaledTouchSlop, getHeight()* 3 / 4 ); itemView.setDrawingCacheEnabled( true ); Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache()); startDrag(bm, x, y); } return false ; } return super .onInterceptTouchEvent(ev); } |
startDrag和stopDrag方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public void startDrag(Bitmap bm, int x, int y){ stopDrag(); windowParams = new WindowManager.LayoutParams(); windowParams.gravity = Gravity.TOP|Gravity.LEFT; windowParams.x = x - dragPointX + dragOffsetX; windowParams.y = y - dragPointY + dragOffsetY; windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; windowParams.format = PixelFormat.TRANSLUCENT; windowParams.windowAnimations = 0 ; ImageView imageView = new ImageView(getContext()); imageView.setImageBitmap(bm); windowManager = (WindowManager)getContext().getSystemService( "window" ); windowManager.addView(imageView, windowParams); dragImageView = imageView; } public void onDrag( int x, int y){ if (dragImageView!= null ){ windowParams.alpha = 0 .8f; windowParams.x = x - dragPointX + dragOffsetX; windowParams.y = y - dragPointY + dragOffsetY; windowManager.updateViewLayout(dragImageView, windowParams); } int tempPosition = pointToPosition(x, y); if (tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //滚动 if (y<upScrollBounce||y>downScrollBounce){ //使用setSelection来实现滚动 setSelection(dragPosition); } } |
7.重写onTouchEvent()方法.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Override public boolean onTouchEvent(MotionEvent ev) { if (dragImageView!= null &&dragPosition!=INVALID_POSITION){ int action = ev.getAction(); switch (action){ case MotionEvent.ACTION_UP: int upX = ( int )ev.getX(); int upY = ( int )ev.getY(); stopDrag(); onDrop(upX,upY); break ; case MotionEvent.ACTION_MOVE: int moveX = ( int )ev.getX(); int moveY = ( int )ev.getY(); onDrag(moveX,moveY); break ; default : break ; } return true ; } return super .onTouchEvent(ev); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void onDrag( int x, int y){ if (dragImageView!= null ){ windowParams.alpha = 0 .8f; windowParams.x = x - dragPointX + dragOffsetX; windowParams.y = y - dragPointY + dragOffsetY; windowManager.updateViewLayout(dragImageView, windowParams); } int tempPosition = pointToPosition(x, y); if (tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //滚动 if (y<upScrollBounce||y>downScrollBounce){ //使用setSelection来实现滚动 setSelection(dragPosition); } } |
在onDrop方法中实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public void onDrop( int x, int y){ //为了避免滑动到分割线的时候,返回-1的问题 int tempPosition = pointToPosition(x, y); if (tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //超出边界处理 if (y<getChildAt( 0 ).getTop()){ //超出上边界 dragPosition = 0 ; } else if (y>getChildAt(getChildCount()- 1 ).getBottom()||(y>getChildAt(getChildCount()- 1 ).getTop()&&x>getChildAt(getChildCount()- 1 ).getRight())){ //超出下边界 dragPosition = getAdapter().getCount()- 1 ; } //数据交换 if (dragPosition!=dragSrcPosition&&dragPosition>- 1 &&dragPosition<getAdapter().getCount()){ DragGridAdapter adapter = (DragGridAdapter)getAdapter(); String dragItem = adapter.getItem(dragSrcPosition); adapter.remove(dragItem); adapter.insert(dragItem, dragPosition); Toast.makeText(getContext(), adapter.getList().toString(), Toast.LENGTH_SHORT).show(); } } |
10.最终效果图如下:

图1

图2
这篇文章也算是前面文章的一个补充和扩展。
分类:
Android学习系列
标签:
Android
, Android学习系列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构