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

来源:互联网 发布:网络污的词语 编辑:程序博客网 时间:2024/05/12 12:56

在Android开发中,我们常常用到ListView和GridView,而有的时候系统的ListView,GridView并不能满足我们的需求,所以我们需要自己定义一个ListView或者GridView,我的上一篇文章中就是自定义的一个左右滑动删除item的例子,大家有兴趣的可以去看看 Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,今天这篇文章就给大家来自定义GridView的控件,GridView主要是来显示网格的控件,在Android的开发中使用很普通,相对于TextView,Button这些控件来说要来的复杂些,今天给大家带来长按GridView的item,然后将其拖拽其他item上面,使得GridView的item发生交换,比较典型的就是我们的Launcher,网上有很多关于GridView的拖动的Demo,但是大部分都是相同的,而且存在一些Bug,而且大部分都是点击GridView的item然后进行拖动,或者item之间不进行实时交换,今天给大家更加详细的介绍GridView拖拽,并且将Demo做的更完美,大家更容易接受,也许很多人听到这个感觉实现起来很复杂,就关掉的这篇文章,其实告诉大家,只要知道了思路就感觉一点都不复杂了,不信大家可以接着往下看看,首先还是跟大家说说实现的思路

 

根据手指按下的X,Y坐标来获取我们在GridView上面点击的item手指按下的时候使用Handler和Runnable来实现一个定时器,假如定时时间为1000毫秒,在1000毫秒内,如果手指抬起了移除定时器,没有抬起并且手指点击在GridView的item所在的区域,则表示我们长按了GridView的item如果我们长按了item则隐藏item,然后使用WindowManager来添加一个item的镜像在屏幕用来代替刚刚隐藏的item当我们手指在屏幕移动的时候,更新item镜像的位置,然后在根据我们移动的X,Y的坐标来获取移动到GridView的哪一个位置到GridView的item过多的时候,可能一屏幕显示不完,我们手指拖动item镜像到屏幕下方,要触发GridView想上滚动,同理,当我们手指拖动item镜像到屏幕上面,触发GridView向下滚动GridView交换数据,刷新界面,移除item的镜像看完上面的这些思路你是不是找到了些感觉了呢,心里痒痒的想动手试试吧,好吧,接下来就带大家根据思路来实现可拖拽的GridView,新建一个项目就叫DragGridView
新建一个类DragGridView继承GridView,先来看看DragGridView的代码,然后在根据代码进行相关的讲解

 

 

?
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
packagecom.example.draggridview;
 
importandroid.annotation.SuppressLint;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.PixelFormat;
importandroid.graphics.Rect;
importandroid.os.Handler;
importandroid.os.Vibrator;
importandroid.util.AttributeSet;
importandroid.view.Gravity;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.WindowManager;
importandroid.widget.AdapterView;
importandroid.widget.GridView;
importandroid.widget.ImageView;
 
/**
 * @blog http://blog.csdn.net/xiaanming
 *
 * @author xiaanming
 *
 */
@SuppressLint(NewApi)
publicclass DragGridView extendsGridView{
    /**
     * DragGridView的item长按响应的时间, 默认是1000毫秒,也可以自行设置
     */
    privatelong dragResponseMS = 1000;
     
    /**
     * 是否可以拖拽,默认不可以
     */
    privateboolean isDrag = false;
     
    privateint mDownX;
    privateint mDownY;
    privateint moveX;
    privateint moveY;
    /**
     * 正在拖拽的position
     */
    privateint mDragPosition;
     
    /**
     * 刚开始拖拽的item对应的View
     */
    privateView mStartDragItemView = null;
     
    /**
     * 用于拖拽的镜像,这里直接用一个ImageView
     */
    privateImageView mDragImageView;
     
    /**
     * 震动器
     */
    privateVibrator mVibrator;
     
    privateWindowManager mWindowManager;
    /**
     * item镜像的布局参数
     */
    privateWindowManager.LayoutParams mWindowLayoutParams;
     
    /**
     * 我们拖拽的item对应的Bitmap
     */
    privateBitmap mDragBitmap;
     
    /**
     * 按下的点到所在item的上边缘的距离
     */
    privateint mPoint2ItemTop ;
     
    /**
     * 按下的点到所在item的左边缘的距离
     */
    privateint mPoint2ItemLeft;
     
    /**
     * DragGridView距离屏幕顶部的偏移量
     */
    privateint mOffset2Top;
     
    /**
     * DragGridView距离屏幕左边的偏移量
     */
    privateint mOffset2Left;
     
    /**
     * 状态栏的高度
     */
    privateint mStatusHeight;
     
    /**
     * DragGridView自动向下滚动的边界值
     */
    privateint mDownScrollBorder;
     
    /**
     * DragGridView自动向上滚动的边界值
     */
    privateint mUpScrollBorder;
     
    /**
     * DragGridView自动滚动的速度
     */
    privatestatic final int speed = 80;
     
    /**
     * item发生变化回调的接口
     */
    privateOnChanageListener onChanageListener;
     
     
     
    publicDragGridView(Context context) {
        this(context,null);
    }
     
    publicDragGridView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    publicDragGridView(Context context, AttributeSet attrs, intdefStyle) {
        super(context, attrs, defStyle);
        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mStatusHeight = getStatusHeight(context); //获取状态栏的高度
    }
     
    privateHandler mHandler = newHandler();
     
    //用来处理是否为长按的Runnable
    privateRunnable mLongClickRunnable = newRunnable() {
         
        @Override
        publicvoid run() {
            isDrag = true;//设置可以拖拽
            mVibrator.vibrate(50);//震动一下
            mStartDragItemView.setVisibility(View.INVISIBLE);//隐藏该item
             
            //根据我们按下的点显示item镜像
            createDragImage(mDragBitmap, mDownX, mDownY);
        }
    };
     
    /**
     * 设置回调接口
     * @param onChanageListener
     */
    publicvoid setOnChangeListener(OnChanageListener onChanageListener){
        this.onChanageListener = onChanageListener;
    }
     
    /**
     * 设置响应拖拽的毫秒数,默认是1000毫秒
     * @param dragResponseMS
     */
    publicvoid setDragResponseMS(longdragResponseMS) {
        this.dragResponseMS = dragResponseMS;
    }
 
    @Override
    publicboolean dispatchTouchEvent(MotionEvent ev) {
        switch(ev.getAction()){
        caseMotionEvent.ACTION_DOWN:
            //使用Handler延迟dragResponseMS执行mLongClickRunnable
            mHandler.postDelayed(mLongClickRunnable, dragResponseMS);
             
            mDownX = (int) ev.getX();
            mDownY = (int) ev.getY();
             
            //根据按下的X,Y坐标获取所点击item的position
            mDragPosition = pointToPosition(mDownX, mDownY);
             
            if(mDragPosition == AdapterView.INVALID_POSITION){
                returnsuper.dispatchTouchEvent(ev);
            }
             
            //根据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);
            //获取mDragItemView在缓存中的Bitmap对象
            mDragBitmap = Bitmap.createBitmap(mStartDragItemView.getDrawingCache());
            //这一步很关键,释放绘图缓存,避免出现重复的镜像
            mStartDragItemView.destroyDrawingCache();
             
             
            break;
        caseMotionEvent.ACTION_MOVE:
            intmoveX = (int)ev.getX();
            intmoveY = (int) ev.getY();
             
            //如果我们在按下的item上面移动,只要不超过item的边界我们就不移除mRunnable
            if(!isTouchInItem(mStartDragItemView, moveX, moveY)){
                mHandler.removeCallbacks(mLongClickRunnable);
            }
            break;
        caseMotionEvent.ACTION_UP:
            mHandler.removeCallbacks(mLongClickRunnable);
            mHandler.removeCallbacks(mScrollRunnable);
            break;
        }
        returnsuper.dispatchTouchEvent(ev);
    }
 
     
    /**
     * 是否点击在GridView的item上面
     * @param itemView
     * @param x
     * @param y
     * @return
     */
    privateboolean isTouchInItem(View dragView, intx, inty){
        intleftOffset = dragView.getLeft();
        inttopOffset = dragView.getTop();
        if(x < leftOffset || x > leftOffset + dragView.getWidth()){
            returnfalse;
        }
         
        if(y < topOffset || y > topOffset + dragView.getHeight()){
            returnfalse;
        }
         
        returntrue;
    }
     
     
 
    @Override
    publicboolean onTouchEvent(MotionEvent ev) {
        if(isDrag && mDragImageView != null){
            switch(ev.getAction()){
            caseMotionEvent.ACTION_MOVE:
                moveX = (int) ev.getX();
                moveY = (int) ev.getY();
                //拖动item
                onDragItem(moveX, moveY);
                break;
            caseMotionEvent.ACTION_UP:
                onStopDrag();
                isDrag = false;
                break;
            }
            returntrue;
        }
        returnsuper.onTouchEvent(ev);
    }
     
     
    /**
     * 创建拖动的镜像
     * @param bitmap
     * @param downX
     *          按下的点相对父控件的X坐标
     * @param downY
     *          按下的点相对父控件的X坐标
     */
    privatevoid createDragImage(Bitmap bitmap, intdownX , intdownY){
        mWindowLayoutParams = newWindowManager.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 = newImageView(getContext()); 
        mDragImageView.setImageBitmap(bitmap); 
        mWindowManager.addView(mDragImageView, mWindowLayoutParams); 
    }
     
    /**
     * 从界面上面移动拖动镜像
     */
    privatevoid removeDragImage(){
        if(mDragImageView != null){
            mWindowManager.removeView(mDragImageView);
            mDragImageView = null;
        }
    }
     
    /**
     * 拖动item,在里面实现了item镜像的位置更新,item的相互交换以及GridView的自行滚动
     * @param x
     * @param y
     */
    privatevoid onDragItem(intmoveX, intmoveY){
        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自动向下滚动
     * 否则不进行滚动
     */
    privateRunnable mScrollRunnable = newRunnable() {
         
        @Override
        publicvoid run() {
            intscrollY;
            if(moveY > mUpScrollBorder){
                 scrollY = -speed;
                 mHandler.postDelayed(mScrollRunnable,25);
            }elseif(moveY < mDownScrollBorder){
                scrollY = speed;
                 mHandler.postDelayed(mScrollRunnable,25);
            }else{
                scrollY = 0;
                mHandler.removeCallbacks(mScrollRunnable);
            }
             
            //当我们的手指到达GridView向上或者向下滚动的偏移量的时候,可能我们手指没有移动,但是DragGridView在自动的滚动
            //所以我们在这里调用下onSwapItem()方法来交换item
            onSwapItem(moveX, moveY);
             
            View view = getChildAt(mDragPosition - getFirstVisiblePosition());
            //实现GridView的自动滚动
            smoothScrollToPositionFromTop(mDragPosition, view.getTop() + scrollY);
        }
    };
     
     
    /**
     * 交换item,并且控制item之间的显示与隐藏效果
     * @param moveX
     * @param moveY
     */
    privatevoid onSwapItem(intmoveX, intmoveY){
        //获取我们手指移动到的那个item的position
        inttempPosition = pointToPosition(moveX, moveY);
         
        //假如tempPosition 改变了并且tempPosition不等于-1,则进行交换
        if(tempPosition != mDragPosition && tempPosition != AdapterView.INVALID_POSITION){
            getChildAt(tempPosition - getFirstVisiblePosition()).setVisibility(View.INVISIBLE);//拖动到了新的item,新的item隐藏掉
            getChildAt(mDragPosition - getFirstVisiblePosition()).setVisibility(View.VISIBLE);//之前的item显示出来
             
            if(onChanageListener != null){
                onChanageListener.onChange(mDragPosition, tempPosition);
            }
             
            mDragPosition = tempPosition;
        }
    }
     
     
    /**
     * 停止拖拽我们将之前隐藏的item显示出来,并将镜像移除
     */
    privatevoid onStopDrag(){
        getChildAt(mDragPosition - getFirstVisiblePosition()).setVisibility(View.VISIBLE);
        removeDragImage();
    }
     
    /**
     * 获取状态栏的高度
     * @param context
     * @return
     */
    privatestatic int getStatusHeight(Context context){
        intstatusHeight = 0;
        Rect localRect = newRect();
        ((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();
                inti5 = Integer.parseInt(localClass.getField(status_bar_height).get(localObject).toString());
                statusHeight = context.getResources().getDimensionPixelSize(i5);
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
        returnstatusHeight;
    }
 
     
    /**
     *
     * @author xiaanming
     *
     */
    publicinterface OnChanageListener{
         
        /**
         * 当item交换位置的时候回调的方法,我们只需要在该方法中实现数据的交换即可
         * @param form
         *          开始的position
         * @param to
         *          拖拽到的position
         */
        publicvoid onChange(intform, intto);
    }
}
首先看DragGridView的事件分发方法,不了解Android事件分发的可以先去了解下,Android事件分发对于自定义控件很重要,简单说下,当我们点击DragGridView的Item,先会去执行dispatchTouchEvent()方法将事件分发下去,所以我们要重写dispatchTouchEvent()方法在手指按下的时候根据pointToPosition()方法来获取我们按下的item的position,根据getChildAt()方法来获取该position上面所对应的View, 并且开启长按的定时器,默认时间为1000毫秒,如果在1000毫秒内手指抬起或者手指在屏幕上滑动出了该item,则取消长按定时器,否则就表示可以进行拖拽,手机友好的震动一下,隐藏我们长按的Item,屏幕调用createDragImage()方法来创建我们长按的item的镜像,创建Item的镜像使用的是WindowManager类,该类可以创建一个窗体显示在Activity之上,
再此之前大家先要理解这几个距离,理解这几个距离之前要首先知道getRawX(),getRawY()和getX(),getY()的区别,getRawX(),getRawY()是相对于屏幕的原点的距离,而getX(),getY()是相对于控件左上方的点的距离,为了方便大家理解我用Word简单的画了下图,画得不好,大家将就的看下,红色框框为我们的GridView

 

/

 

mPoint2ItemTop 手指按下的点到该Item的上边缘的距离,如上图的1号线mPoint2ItemLeft 手指按下的点到该Item的左边缘的距离,如上图的2号线mOffset2Top DragGridView的上边缘到屏幕上边缘的距离,如上图的3号线,这个距离包裹状态栏,标题栏,或者一些在DragGridView上面的布局的高度,这个很重要我们现实Item镜像需要用到mOffset2Left DragGridView的左边缘到屏幕左边缘的距离,如上图的4号线,我这个Demo的这个距离为0,因为我设置DragGridView的宽度为充满屏幕,但是我们要考虑假如DragGridView与屏幕左边缘设置了间隙或者左边有其他的布局的情形mDownScrollBorder 这个距离表示当DragGridView的item过多的时候,手机一屏显示不完全,我们拖动Item镜像到这个高度的时候,DragGridView自动向下滚动,如上图的5号线.mUpScrollBorder 这个和mDownScrollBorder相反,当我们大于这个高度的时候,DragGridView自动向上滚动,如上图的6号线理解了这六个距离,我们就来看看创建Item镜像的方法里面,其他的我不多说,首先设置format为PixelFormat.TRANSLUCENT,表示除了我们显示图片和文字的其他地方为透明,之后就是x,y这两个距离的计算,计算的是item的左上角的坐标,理解了上面这六个距离我们很容易得出x,y的坐标,可是你会发现y的坐标减去了状态栏的高度,这点大家需要注意下,另外我们需要获取item的绘制缓存的Bitmap对象,然后将Bitmap设置到一个ImageView上面,为什么要这么做呢?如果调用addView()方法将item 直接添加到WindowManager里面,会有异常产生,因为item已经有了自己归属的父容器DragGridView,所有我们这里使用一个ImageView来代替item添加到WindowManager里面

上面已经完成了开始拖拽的准备工作,要想拖动镜像我们还需要重写onTouchEvent()方法,获取移动的X,Y的坐标,利用WindowManager的updateViewLayout方法就能对镜像进行拖动,拖动的镜像的时候为了有更好的用户体验,我们还要做item的实时交换效果,我们利用手指移动的X,Y坐标,利用pointToPosition()来获取拖拽到的position,然后将之前的item显示出来,将拖拽到的item进行隐藏,这样子就完成了item在界面上面的交换,但是数据交换我这里没有做,所以我提供了回调接口OnChanageListener,我们只需要自己实现数据的交换逻辑然后刷新DragGridView即可,我们还需要实现DragGridView的自动向上滚动或者向下滚动,使用Handler和mScrollRunnable利用smoothScrollToPositionFromTop来实现DragGridView滚动,具体的实现大家可以看代码
手指离开界面,将item的镜像移除,并将拖拽到的item显示出来,这样子就实现了GirdView的拖拽效果啦,接下来我们来使用下我们自定义可拖拽的GridView吧,先看主界面布局,只有我们自定义的一个DragGridView
?
1
2
3
4
5
6
<relativelayout android:layout_height="match_parent"android:layout_width="match_parent"xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools">
 
    <com.example.draggridview.draggridview android:cachecolorhint="@android:color/transparent"android:gravity="center"android:horizontalspacing="10dip"android:id="@+id/dragGridView"android:layout_height="match_parent"android:layout_width="match_parent"android:listselector="@android:color/transparent"android:numcolumns="3"android:stretchmode="columnWidth"android:verticalspacing="10dip">
    </com.example.draggridview.draggridview>
 
</relativelayout>
接下来我们看看DragGridView的item的布局,上面一个ImageView下面一个TextView
?
1
2
3
4
5
6
7
8
9
10
<!--?xml version=1.0encoding=utf-8?-->
<relativelayout android:background="@android:color/transparent"android:layout_height="wrap_content"android:layout_width="fill_parent"xmlns:android="http://schemas.android.com/apk/res/android">
 
    <imageview android:id="@+id/item_image"android:layout_centerhorizontal="true"android:layout_height="wrap_content"android:layout_width="wrap_content"android:scaletype="centerCrop">
    </imageview>
 
    <textview android:id="@+id/item_text"android:layout_below="@+id/item_image"android:layout_centerhorizontal="true"android:layout_height="wrap_content"android:layout_width="wrap_content">
    </textview>
 
</relativelayout>
布局搞定了我们就来看看主页面MainActivity的代码吧
?
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
packagecom.example.draggridview;
 
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.List;
 
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.SimpleAdapter;
 
importcom.example.draggridview.DragGridView.OnChanageListener;
 
/**
 * @blog http://blog.csdn.net/xiaanming
 *
 * @author xiaanming
 *
 */
publicclass MainActivity extendsActivity {
    privateList<hashmap<string, object="">> dataSourceList = newArrayList<hashmap<string, object="">>();
 
    @Override
    protectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        DragGridView mDragGridView = (DragGridView) findViewById(R.id.dragGridView);
        for(inti = 0; i < 30; i++) {
            HashMap<string, object=""> itemHashMap = newHashMap<string, object="">();
            itemHashMap.put(item_image,R.drawable.com_tencent_open_notice_msg_icon_big);
            itemHashMap.put(item_text, 拖拽  + Integer.toString(i));
            dataSourceList.add(itemHashMap);
        }
         
 
        finalSimpleAdapter mSimpleAdapter = newSimpleAdapter(this, dataSourceList,
                R.layout.grid_item,newString[] { item_image, item_text },
                newint[] { R.id.item_image, R.id.item_text });
         
        mDragGridView.setAdapter(mSimpleAdapter);
         
        mDragGridView.setOnChangeListener(newOnChanageListener() {
             
            @Override
            publicvoid onChange(intfrom, intto) {
                HashMap<string, object=""> temp = dataSourceList.get(from);
                //直接交互item
//              dataSourceList.set(from, dataSourceList.get(to));
//              dataSourceList.set(to, temp);
//              dataSourceList.set(to, temp);
                 
                 
                //这里的处理需要注意下
                if(from < to){
                    for(inti=from; i<to; else=""from=""> to){
                    for(inti=from; i>to; i--){
                        Collections.swap(dataSourceList, i, i-1);
                    }
                }
                 
                dataSourceList.set(to, temp);
                 
                mSimpleAdapter.notifyDataSetChanged();
                 
                 
            }
        });
         
    }
 
}
</to;></string,></string,></string,></hashmap<string,></hashmap<string,>
这里面的代码还是比较简单,主要讲下onChange()方法,我们要为mDragGridView设置一个OnChanageListener的回调接口,在onChange()方法里面实现数据的交换逻辑,第一个参数from为item开始的位置,第二个参数to为item拖拽到的位置,刚开始我使用的交换逻辑是
?
1
2
3
4
HashMap<string, object=""> temp = dataSourceList.get(from);
                //直接交互item
//              dataSourceList.set(from, dataSourceList.get(to));
//              dataSourceList.set(to, temp);</string,>
直接交换的item的数据,然后看了下网易新闻的拖拽的GridView,他不是直接实现两个item直接的数据交换,所以将数据交换逻辑改成了下面的方式
简单说下,数据的交换逻辑,比如我们将position从5拖拽到7这个位置,我注释掉的逻辑是直接将5和7的数据交换,而后面的那种逻辑是将6的位置数据移动到5,将7的位置移动到6,然后再7显示5 6->5, 7->6, 5->7不知道大家理解了没有。接下来我们来运行下项目,在运行之前我们不要忘了在AndroidManifest.xml里面加入震动的权限/


好了,今天的讲解就到此结束,效果还不错吧,看完这篇文章你是不是觉得GridView拖拽也不是那么难实现呢?你心里是不是也大概有自己的一个思路,建议大家自己敲敲看看,可以自己去实现下ListView的拖拽实现,ListView比GridView简单些,好的学习方法不是看得懂人家的代码,而是看完代码自己根据脑海里的思路自己敲出来,所以还是鼓励大家多敲代码,不明白的同学在下面留言,我会为大家解答的!
0 0
原创粉丝点击