Implement the drag-and-drop GridView effect for Android, and enable real-time exchange of drag-and-drop and item by long-pressed

Source: Internet
Author: User
Tags gety

Post please indicate this article from xiaanming blog (http://blog.csdn.net/xiaanming/article/details/17718579), please respect others' hard work results, thank you!

In Android development, ListView and GridView are often used. Sometimes the system ListView and GridView cannot meet our needs. Therefore, we need to define a ListView or GridView by ourselves, in my previous article, I used a custom example of sliding left and right to delete items. If you are interested, you can see that Android uses Scroller to achieve the brilliant effect of sliding left and right to delete items, today, this article will give you a custom control for the GridView. The GridView is mainly used to display grid controls, which are common in Android development. Compared with TextView, buttons are more complicated. Today, we bring you a long-pressed GridView item, and drag it onto other items to exchange the items in the GridView, A typical example is our Launcher. There are a lot of demos about the drag of the GridView on the Internet, but most of them are the same, and there are some bugs, and most of them are clicked on the items of the GridView and then dragged, or there is no real-time exchange between items. Today we will give you a more detailed introduction of the GridView drag and drop, and make the Demo more perfect and easier for everyone to accept, this article may be closed when many people hear that it is complicated to implement. In fact, it tells everyone that it is not complicated to understand the idea. If you don't believe it, let's take a look at it, first, let's talk about the Implementation ideas.

 

After reading the above ideas, have you found some feelings? I want to give it a try. Well, next I will show you how to implement the drag-and-drop GridView based on your ideas, create a project called DragGridView
Create a new class DragGridView to inherit the GridView. Let's take a look at the code of DragGridView, and then explain it according to the code.

Package com. example. draggridview; import android. annotation. suppressLint; 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. text. getChars; 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;/*** @ blog http://blog.csdn.net/xiaanming *** @ author xiaanming ***/@ SuppressLint ("NewApi ") public class DragGridView extends GridView {/*** long response time of the DragGridView item. The default value is 1000 milliseconds. You can also set */private long dragResponseMS = 1000; /*** can be dragged or dragged? It is not supported by default */ Private boolean isDrag = false; private int mDownX; private int mDownY; private int moveX; private int moveY;/*** position being dragged */private int mDragPosition; /* View */private View mStartDragItemView = null for the item to be dragged;/* use an ImageView */private ImageView mDragImageView to drag the image; /* Vibrator */private Vibrator mVibrator; private WindowManager mWindowManager;/* layout parameter of the item image */private WindowManage R. layoutParams mWindowLayoutParams;/*** Bitmap */private Bitmap mDragBitmap corresponding to the item we drag;/*** the distance from the pressed point to the top edge of the item */private int mPoint2ItemTop; /*** the distance between the pressed point and the left edge of the item */private int mPoint2ItemLeft;/*** the offset of DragGridView from the top of the screen */private int mOffset2Top; /*** offset of DragGridView from the left of the screen */private int mOffset2Left;/*** height of the status bar */private int mStatusHeight; /*** automatically scroll down the DragGridView Boundary Value */private int mDow NScrollBorder;/*** automatically scroll up boundary value of DragGridView */private int mUpScrollBorder;/*** automatically scroll speed of DragGridView */private static final int speed = 80; /*** interface for callback of item change */private OnChanageListener onChanageListener; public DragGridView (Context context) {this (context, null);} public DragGridView (Context context, AttributeSet attrs) {this (context, attrs, 0);} public DragGridView (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); // get the height of the status bar} private Handler mHandler = new Handler (); // Runnableprivate Runnable mLongClickRunnable = new Runnable () {@ Overridepublic void run () {IsDrag = true; // you can drag mVibrator. vibrate (50); // shake the mStartDragItemView. setVisibility (View. INVISIBLE); // hide this item // display the item image createDragImage (mDragBitmap, mDownX, mDownY) according to the point we press );}}; /*** set the callback interface * @ param onChanageListener */public void setOnChangeListener (OnChanageListener onChanageListener) {this. onChanageListener = onChanageListener;}/*** sets the number of milliseconds to drag a response. The default value is 1000 milliseconds * @ param dragResponseMS */public void set DragResponseMS (long dragResponseMS) {this. dragResponseMS = dragResponseMS;} @ Overridepublic boolean dispatchTouchEvent (MotionEvent ev) {switch (ev. getAction () {case MotionEvent. ACTION_DOWN: // use Handler to delay dragResponseMS and execute mLongClickRunnablemHandler. postDelayed (mLongClickRunnable, dragResponseMS); mDownX = (int) ev. getX (); mDownY = (int) ev. getY (); // obtain the positionmDragPosition = pointToPositi of the clicked item based on the X and Y coordinates of the pressed item. On (mDownX, mDownY); if (mDragPosition = AdapterView. INVALID_POSITION) {return super. dispatchTouchEvent (ev);} // obtain the corresponding ViewmStartDragItemView = getChildAt (mDragPosition-getFirstVisiblePosition () of the item based on position ()); // you can refer to the figure above in my blog to understand mPoint2ItemTop = mDownY-mStartDragItemView. getTop (); mPoint2ItemLeft = mDownX-mStartDragItemView. getLeft (); mOffset2Top = (int) (ev. getRawY ()-mDownY); mOffset2Lef T = (int) (ev. getRawX ()-mDownX); // get the offset of DragGridView auto-scroll up. If the offset is smaller than this value, DragGridView rolls down mDownScrollBorder = getHeight ()/4; // get the offset of DragGridView auto-scroll down. If it is greater than this value, DragGridView will scroll up mUpScrollBorder = getHeight () * 3/4; // open the mDragItemView drawing cache mStartDragItemView. setDrawingCacheEnabled (true); // gets the Bitmap object mDragBitmap = Bitmap in the cache. createBitmap (mStartDragItemView. getDrawingCache (); // this step is critical. Release the drawing cache to avoid repeated image m. StartDragItemView. destroyDrawingCache (); break; case MotionEvent. ACTION_MOVE: int moveX = (int) ev. getX (); int moveY = (int) ev. getY (); // if we move above the item that is pressed, we will not remove mRunnableif (! IsTouchInItem (mStartDragItemView, moveX, moveY) {mHandler. removeCallbacks (mLongClickRunnable);} break; case MotionEvent. ACTION_UP: mHandler. removeCallbacks (mLongClickRunnable); mHandler. removeCallbacks (mScrollRunnable); break;} return super. dispatchTouchEvent (ev );} /*** click ** @ param itemView * @ param x * @ param y * @ return */private boolean isTouchInItem (View dragView, int x, int y) {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;} @ Overridepublic boolean onTouchEvent (MotionEvent ev) {if (isDrag & mDragImageView! = Null) {switch (ev. getAction () {case MotionEvent. ACTION_MOVE: moveX = (int) ev. getX (); moveY = (int) ev. getY (); // drag itemonDragItem (moveX, moveY); break; case MotionEvent. ACTION_UP: onStopDrag (); isDrag = false; break;} return true;} return super. onTouchEvent (ev );} /*** create a dragged image * @ param bitmap * @ param downX * The X coordinate of the Point pressed relative to the parent control * @ param downY * The Point pressed relative to the X coordinate of the parent Control */private void createDragImage (Bitmap bitmap, int downX, Int downY) {mWindowLayoutParams = new WindowManager. layoutParams (); mWindowLayoutParams. format = PixelFormat. TRANSLUCENT; // transparent mWindowLayoutParams outside the image. gravity = Gravity. TOP | Gravity. LEFT; mWindowLayoutParams. x = downX-mPoint2ItemLeft + mOffset2Left; mWindowLayoutParams. y = downY-mPoint2ItemTop + mOffset2Top-mStatusHeight; mWindowLayoutParams. alpha = 0.55f; // transparency 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);}/*** move the image from the interface */Private void removeDragImage () {if (mDragImageView! = Null) {mWindowManager. removeView (mDragImageView); mDragImageView = null;}/*** drag an item to update the position of the item image, exchange of items and self-rolling of the 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 (mDragImageView, mWindowLayout Params); // update the Image Location onSwapItem (moveX, moveY); // The GridView automatically scrolls the mHandler. post (mScrollRunnable);}/*** when the moveY value is greater than the scroll up boundary value, the GridView is triggered to automatically scroll up * When the moveY value is smaller than the scroll down boundary value, automatically scroll down in violation of the GridView * otherwise do not scroll */private Runnable mScrollRunnable = new Runnable () {@ Overridepublic void run () {int scrollY; if (moveY> mUpScrollBorder) {scrollY =-speed; mHandler. postDelayed (mScrollRunnable, 25);} else if (moveY <mDownScrollBorder) {scr OllY = speed; mHandler. postDelayed (mScrollRunnable, 25);} else {scrollY = 0; mHandler. removeCallbacks (mScrollRunnable);} // when our fingers reach the offset of the up or down scroll of the GridView, our fingers may not move, but DragGridView is automatically scrolling // so here we call the onSwapItem () method to exchange itemonSwapItem (moveX, moveY); View view = getChildAt (mDragPosition-getFirstVisiblePosition ()); // implement automatic scrolling of the GridView smoothScrollToPositionFromTop (mDragPosition, view. getTop () + scrollY );}};/** * Swap items and control the display and hide effects between items * @ param moveX * @ param moveY */private void onSwapItem (int moveX, int moveY) {// obtain the positionint tempPosition = pointToPosition (moveX, moveY) of the item to which our fingers move; // If tempPosition is changed and tempPosition is not equal to-1, if (tempPosition! = MDragPosition & tempPosition! = AdapterView. INVALID_POSITION) {getChildAt (tempPosition-getFirstVisiblePosition ()). setVisibility (View. INVISIBLE); // drag the new item to hide getChildAt (mDragPosition-getFirstVisiblePosition ()). setVisibility (View. VISIBLE); // if (onChanageListener! = Null) {onChanageListener. onChange (mDragPosition, tempPosition);} mDragPosition = tempPosition;}/*** stop dragging. We will display the hidden items and remove the image */private void onStopDrag () {getChildAt (mDragPosition-getFirstVisiblePosition ()). setVisibility (View. VISIBLE); removeDragImage ();}/*** get the height of the status bar * @ param context * @ return */private static int getStatusHeight (Context context) {int statusHeight = 0; rect localRect = new Re Ct (); (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 {/*** callback method when the item is switched to a position, we only need to implement data exchange in this method to * @ param form * start position * @ param to * drag to position */public void onChange (int form, int );}}

First, let's look at the event Distribution Method of DragGridView. If you don't know about Android event distribution, You can first understand it. Android event distribution is very important for custom controls. To put it simply, when we click the Item of DragGridView, we will first execute the dispatchTouchEvent () method to distribute the event, so we need to rewrite the dispatchTouchEvent () method to obtain the position of the item we press based on the pointToPosition () method when the finger is pressed, obtain the View corresponding to the position according to the getChildAt () method, and enable the timer of Long-pressed. The default time is 1000 milliseconds, if the finger is raised within 1000 milliseconds or the finger slides out of the item on the screen, cancel the long-pressed timer. Otherwise, it indicates that you can drag and drop the item, and the mobile phone will shake it, hide the long-pressed Item. Call the createDragImage () method on the screen to create the image of the long-pressed item. The image for creating the Item uses the WindowManager class, this class can create a form that is displayed on the Activity,
Before that, you must understand these distances. Before understanding these distances, you must first know the differences between getRawX (), getRawY (), getX (), and getY, getRawX (), getRawY () is the distance from the screen origin, while getX () and getY () are the distance from the point in the upper-left corner of the control, for the convenience of understanding, I used Word to draw a simple image. If the painting is not good, you will take a look at it. The red box is our GridView.

Next, let's take a look at the layout of the items in DragGridView. The TextView under the above ImageView

<?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="@android:color/transparent" >    <ImageView        android:id="@+id/item_image"        android:scaleType="centerCrop"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true" >    </ImageView>    <TextView        android:id="@+id/item_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@+id/item_image"        android:layout_centerHorizontal="true" >    </TextView></RelativeLayout>

After the layout is completed, let's take a look at the MainActivity code on the home page.

Package com. example. draggridview; import java. util. arrayList; import java. util. collections; import java. util. hashMap; import java. util. list; import android. app. activity; import android. OS. bundle; import android. widget. simpleAdapter; import com. example. draggridview. dragGridView. onChanageListener;/*** @ blog http://blog.csdn.net/xiaanming *** @ author xiaanming ***/public class MainActivity extends Activity {private List <HashMap <String, object> canccelist = new ArrayList <HashMap <String, Object> (); @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DragGridView mDragGridView = (DragGridView) findViewById (R. id. dragGridView); for (int I = 0; I <30; I ++) {HashMap <String, Object> itemHashMap = new HashMap <String, Object> (); itemHashMap. put ("item_image", R.drawable.com _ tencent_open_notice_msg_icon_big); itemHashMap. put ("item_text", "drag" + Integer. toString (I); dataSourceList. add (itemHashMap);} final SimpleAdapter mSimpleAdapter = new SimpleAdapter (this, dataSourceList, R. layout. grid_item, new String [] {"item_image", "item_text"}, new int [] {R. id. item_image, R. id. item_text}); mDragGridView. setAdapter (mSimpleAdapter); mDragGridView. setOnChangeListener (new OnChanageListener () {@ Overridepublic void onChange (int from, int to) {HashMap <String, Object> temp = dataSourceList. get (from); // Directly Interacts with item // dataSourceList. set (from, dataSourceList. get (to); // dataSourceList. set (to, temp); // dataSourceList. set (to, temp); // for processing here, pay attention to if (from <to) {for (int I = from; I <to; I ++) {Collections. swap (dataSourceList, I, I + 1) ;}} else if (from> to) {for (int I = from; I> to; I --) {Collections. swap (dataSourceList, I, I-1) ;}} dataSourceList. set (to, temp); mSimpleAdapter. notifyDataSetChanged ();}});}}

The code here is relatively simple. We will mainly talk about the onChange () method. We will set a callback interface of OnChanageListener for the mDragGridView to implement the data exchange logic in the onChange () method, the first parameter from is the start position of the item, and the second parameter to is the drag position of the item. The switch logic I used at the beginning is

HashMap <String, Object> temp = dataSourceList. get (from); // Directly Interacts with item // dataSourceList. set (from, dataSourceList. get (to); // dataSourceList. set (to, temp );

  

After reading the drag-and-drop GridView of Netease news, the data exchange logic is changed to the following method.
To put it simply, the data exchange logic, for example, we drag position from 5 to 7, and the logic I comment out is to directly exchange the data between 5 and 7, the logic behind this is to move the data at Location 6 to Location 5, move the data at location 7 to Location 6, and then display 5 6-> 5, 7-> 6, 5-> 7. I don't know if you understand it. Next, let's run the project. Before running it, we should not forget to run it in AndroidManifest. the vibration permission <uses-permission android: name = "android. permission. VIBRATE "/> I am honored to be CSDN 2013 blog Star SelectionHope to continue to get everyone's support and encouragement. If you see a friend, please vote for me!

Voting address: Http://vote.blog.csdn.net/blogstaritem/blogstar2013/xiaanming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.