Custom View for Android Development (III): Custom GridView
As a common component in android development, gridview has powerful functions. However, we sometimes have many special requirements that need to be transformed. Sometimes there is a need to move the item position in the gridView. There are already many examples on the Internet, so the bloggers will not describe them. Today, Bo is talking about moving the content in items in the gridView. The blogger hasn't seen the demos of those mobile items on the Internet. He doesn't know whether the principles are the same as those of the blogger. The blogger thought that it seems that this implementation principle of the blogger can also be used to implement the moving item position. However, it seems that this principle can also be applied to the customized disordered emissions of Xiaomi mobile phones that bloggers cannot solve. Okay, you don't have to talk about it.
Here, the blogger uses numbers as the content for demonstration. The background colors of different digital items are different. after holding a long item, you can move it. Each time you move the item, the moving item is reduced by 1, add 1 to the item to be moved. The effect is okay. Now, let's get started with the code. If you know how it works, you can modify the code to develop a gridView that can move items.
Complete Project: www.bkjia.com
(The network is not powerful recently, and there is a problem with github uploading. Wait until the last custom view topic will be explained tomorrow, and upload all the projects together. If you don't mind, you can download them first)
Package com. freedom. gridview; import android. annotation. suppressLint; import android. content. context; import android. graphics. bitmap; import android. graphics. pixelFormat; import android. util. attributeSet; import android. view. gravity; import android. view. motionEvent; import android. view. view; import android. view. viewConfiguration; import android. view. viewGroup; import android. view. windowManager; import android. View. animation. animationUtils; import android. widget. adapterView; import android. widget. gridView; import android. widget. imageView; import android. widget. toast; import com. freedom. gridview. adapter. gridViewAdapter; import com. freedom. gridview. bean. data;/*** @ ClassName: FreedomGridView * @ author ← _freedom (x_freedom_reddevil@126.com) * @ createddate 10:25:52 * @ Description: gridVi that can move item content Ew */@ SuppressLint (NewApi) public class FreedomGridView extends GridView {// whether to move private boolean isMove = false; // whether to move private boolean isFirst = true for the first time; // whether to press private boolean isLongClick = false; // The image private Bitmap bitmap; // move the view private ImageView moveView = null; // offset private int offsetX, offsetY; // position of the touch on the screen: private int touchPositionInScreen; // position of the target to be moved: private int moveToPosition; // coordinates touched in the ITEM Private int touchPositionInItemX, touchPositionInItemY; // The moving speed is private int scaledTouchSlop; // The moving margin determines the automatic sliding distance from private int upScrollBounce; private int downScrollBounce; // form manager, used to add a view private WindowManager windowManager = null; private WindowManager. layoutParams layoutParams = null; private GridViewAdapter adapter; public FreedomGridView (Context context) {super (context); scaledTouchSlop = ViewConfigurat Ion. get (context ). getScaledTouchSlop ();} public FreedomGridView (Context context, AttributeSet attrs) {super (context, attrs);} public FreedomGridView (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle);}/*** long press decision */private Runnable longPressRun = new Runnable () {@ Overridepublic void run () {isLongClick = true ;}}; /*** @ Title: contains * @ Description: determines whether to touch the coordinates in the view *@ Param v * @ param xInView * @ param yInView * @ return * @ throws */private boolean contains (View v, int xInView, int yInView) {if (v instanceof ImageView) {return (ImageView) v ). getDrawable (). getBounds (). contains (xInView, yInView);} return v. getBackground (). getBounds (). contains (xInView, yInView) ;}@ Overridepublic boolean onTouchEvent (MotionEvent ev) {// get the adapter if (null = adapter | adapter. isEmpty ()){ Adapter = (GridViewAdapter) getAdapter ();} switch (ev. getAction () {case MotionEvent. ACTION_DOWN: // get the coordinate int x = (int) ev relative to the touch view. getX (); int y = (int) ev. getY (); // get the touch position touchPositionInScreen = moveToPosition = this. pointToPosition (x, y); // determines whether the position is valid if (moveToPosition = AdapterView. INVALID_POSITION) {break;} // obtain the visible itemViewGroup itemView = (ViewGroup) this. getChildAt (moveToPosition-this. getFirs TVisiblePosition (); // get the offset of the click position relative to the ITEM view touchPositionInItemY = y-itemView. getTop (); touchPositionInItemX = x-itemView. getLeft (); // get the control View = itemView in the item view. findViewById (R. id. __back); // determines whether the click position is in the view if (this. contains (view, touchPositionInItemX, touchPositionInItemX) {try {int [] locationInScreen = new int [2]; view. getLocationOnScreen (locationInScreen);} catch (NullPointerException e) {Break ;}// offset this when the view is moved. offsetX = (int) (ev. getRawX ()-x); this. offsetY = (int) (ev. getRawY ()-y); // get the margin of the automatically scrolling view that is triggered when you drag the view to the top or bottom. upScrollBounce = Math. min (y-scaledTouchSlop, getHeight ()/3); downScrollBounce = Math. max (y + scaledTouchSlop, getHeight () * 2/3); itemView. setDrawingCacheEnabled (true); // take the bitmapbitmap = Bitmap of the item view. createBitmap (itemView. getDrawingCache (); itemView. destroyDrawi NgCache (); postDelayed (longPressRun, 1000); break; case MotionEvent. ACTION_MOVE: if (isLongClick) {int mx = (int) ev. getX (); int my = (int) ev. getY (); // move for the first time. Create the moving view if (isFirst) initWindowManager (bitmap, mx, my); onMove (mx, my ); // remove the previous runableremoveCallbacks (longPressRun); return true;} break; case MotionEvent. ACTION_UP: int upY = (int) ev. getY (); int upX = (int) ev. getX (); if (isMove & isLongClick) {stopMove (); CompleteMove (upX, upY); isMove = false; isLongClick = false; break;} removeCallbacks (longPressRun);} return super. onTouchEvent (ev);}/*** @ Title: initWindowManager * @ Description: create a mobile view * @ param bm * @ param x * @ param y * @ throws */public void initWindowManager (Bitmap bm, int x, int y) {stopMove (); isFirst = false; layoutParams = new WindowManager. layoutParams (); layoutParams. gravity = Gravity. TOP | G Ravity. LEFT; layoutParams. horizontalMargin = layoutParams. verticalMargin = 0; layoutParams. x = x-touchPositionInItemX + offsetX; layoutParams. y = y-touchPositionInItemY + offsetY; layoutParams. width = WindowManager. layoutParams. WRAP_CONTENT; layoutParams. height = WindowManager. layoutParams. WRAP_CONTENT; layoutParams. flags = WindowManager. layoutParams. FLAG_NOT_FOCUSABLE | WindowManager. layoutParams. FL AG_NOT_TOUCHABLE | WindowManager. layoutParams. FLAG_KEEP_SCREEN_ON | WindowManager. layoutParams. FLAG_LAYOUT_NO_LIMITS; layoutParams. format = PixelFormat. TRANSLUCENT; layoutParams. windowAnimations = 0; windowManager = (WindowManager) this. getContext (). getSystemService (window); ImageView moveViewTemp = new ImageView (getContext (); moveViewTemp. setImageBitmap (bm); windowManager = (WindowManager) this. getConte Xt (). getSystemService (window); windowManager. addView (moveViewTemp, layoutParams); moveView = moveViewTemp;}/*** @ Title: stopMove * @ Description: Stop moving * @ throws */public void stopMove () {if (moveView! = Null) {windowManager. removeView (moveView); moveView = null;}/*** @ Title: onMove * @ Description: method triggered when the view is moved * @ param x * @ param y * @ throws */public void onMove (int x, int y) {isMove = true; // Avoid dragging to the invalid area int tempPosition = this. pointToPosition (x, y); if (tempPosition! = FreedomGridView. INVALID_POSITION) {this. moveToPosition = tempPosition;} // update the view position when moving. if (moveView! = Null) {layoutParams. alpha = 0.8f; layoutParams. y = y-touchPositionInItemY + offsetY; layoutParams. x = x-touchPositionInItemX + offsetX; windowManager. updateViewLayout (moveView, layoutParams);} int scrollHeight = 0; if (y <upScrollBounce) {scrollHeight = 30;} else if (y> downScrollBounce) {scrollHeight =-30 ;} // trigger auto-scroll if (scrollHeight! = 0) {smoothScrollToPositionFromTop (moveToPosition, getChildAt (moveToPosition-getFirstVisiblePosition ()). getTop () + scrollHeight, 1) ;}/ *** @ Title: completeMove * @ Description: when the move is completed, * @ param x * @ param y * @ throws */public void completeMove (int x, int y) {isFirst = true; // get the stop position int tempPosition = this. pointToPosition (x, y); if (tempPosition! = FreedomGridView. INVALID_POSITION) {this. moveToPosition = tempPosition;} if (y <getChildAt (0 ). getTop () {return;} else if (y> getChildAt (getChildCount ()-1 ). getBottom () {moveToPosition = getAdapter (). getCount ()-1; return;} else {// if it is in the valid position if (moveToPosition> = 0 & moveToPosition <getAdapter (). getCount () {ViewGroup itemView = (ViewGroup) this. getChildAt (moveToPosition-this. getFirstVisiblePo Sition (); if (itemView! = Null) {ImageView imaveView = (ImageView) itemView. findViewById (R. id. optional _back); // determines whether the view is moved into the valid view. boolean isIn = this. contains (imaveView, x-itemView. getLeft (), y-itemView. getTop (); // if it has already been moved in and is not the starting position of the touch. if (isIn) {if (moveToPosition! = TouchPositionInScreen) {itemView. startAnimation (AnimationUtils. loadAnimation (getContext (), R. anim. desk_scale); Data touchData = (Data) adapter. getItem (touchPositionInScreen); if (touchData. getNum () = 0) {Toast. makeText (getContext (), the number is 0 and cannot be changed, Toast. LENGTH_SHORT ). show (); return;} Data toData = (Data) adapter. getItem (moveToPosition); if (toData. getNum () = 2) {Toast. makeText (getContext (), the number is 2 and cannot be changed, Toast. LENGTH_SHORT ). show (); return;} touchData. setNum (touchData. getNum ()-1); toData. setNum (toData. getNum () + 1); adapter. notifyDataSetChanged ();}}}}}}}