編輯:關於Android編程
之前實現過一個仿支付寶界面的代碼,可拖動網格視圖。其實實現的原理網上都可以找到,我也是參考網上實現的方法,實現了自己需要的界面。並對實現的原理和方法進行了分析,現在進行總結,放太久都快忘記自己做過這回事了。原理和實現網上大部分地方都可以找到,我是根據自己的理解進行分析的,現在對之前的工作進行總結,了解實現的基本過程和方法。GridView拖動的源碼來源於網上,根據需求修改成了需要的效果,下面簡單說明下實現過程。
在說明實現之前,先上一張總體的界面效果圖:
為了更好說明程序種各個變量的意義,我把界面增加了一個縮進,效果如下
實現的原理並不復雜,通過GridView提供的基本方法、一些動畫的基本操作以及移動時邏輯的判斷和處理即可實現,為了更好說明代碼實現的原理,對代碼中使用的一些變量進行說明,參考下面這張圖,時間倉促,隨便畫的,是想更好說明問題。。
從上圖可以看出相關參數的實際意義,下面將從ACTION_DOWN,ACTION_MOVE,ACTION_UP這三個常用的action分析拖動GridView的基本流程。
在ACTION_DOWN觸發的時候,這裡保存了手指按下的坐標:
screenX= (int)ev.getX(); screenY= (int)ev.getY();
另外一個設置了長按監聽,可以參考代碼中setOnItemClickListener()方法。
在這個方法裡,首先保存了按下子View的寬和高:
itemHeight = dragItem.getHeight(); itemWidth = dragItem.getWidth();
這個用於後續計算網格移動的距離。
保存按下點相對於按下子View的x,y坐標:
touchItemX= screenX- dragItem.getLeft(); touchItemY= screenY- dragItem.getTop();
這個主要使用來計算之後隨手勢拖動圖片的位置。
如果是長按,代表已經觸發了拖動過程,這個時候需要根據按下子View的顯示內容創建一張圖片,這張圖片是用來隨手勢拖動顯示的。View類提供了getDrawingCache()方法來獲取一個View的的顯示緩存,它返回的是一個bitmap的引用,而我們可以使用這個返回值創建一個自己的bitmap。
dragItem.destroyDrawingCache(); dragItem.setDrawingCacheEnabled(true); Bitmap dragBitmap = Bitmap.createBitmap(dragItem.getDrawingCache());
創建完成移動的bitmap之後,還需要初始化一些參數值,包括移動的位置,對齊方式,創建一個ImageView來隨手勢拖動,這樣以後每次拖動的時候只要設置隨移動點移動就可以了。
ImageView iv = newImageView(getContext()); iv.setImageBitmap(dragBitmap); // 設置bitmap windowManager = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE); windowManager.addView(iv, windowParams); dragImageView= iv; // 拖動的Item
之後把按下的子View隱藏起來,因為這個時候已經創建子View的一張圖片,看起來就好像子View隨按下動作彈起來了一樣。
在移動手勢的時候,主要完成兩方面的事情,一是手指移動時點擊的圖標會隨手勢移動,二是當移動滿足一定條件是,子View會自動調整自己的位置。
2.1 圖標隨手勢移動
圖標隨手勢移動時調用updateViewLayout()方法,它會根據傳入的參數更新View顯示的位置。
private void onDrag(int x,int y, int rawx,int rawy) { if (dragImageView !=null) { windowParams.alpha = 0.6f; windowParams.x = rawx -touchItemX; // 獲取最新的 windowParams.y = rawy -touchItemY; windowManager.updateViewLayout(dragImageView,windowParams); // 讓dragImageView隨手指拖動 } }
2.2根據手勢移動坐標更新子View的位置
接著需要根據手勢移動最新位置來調整GridView的項目,需要處理下面幾項內容:
1.獲取當前拖動的拖動x,y對應GridView的位置,使用pointToPosition()方法獲取。
int dPosition = pointToPosition(x, y);
2.計算當前拖動的x,y坐標位置需要移動多少個子View,使用上面計算出來的位置減去初始位置,得到的差值就是需要移動的子View數目,取絕對值
movecount= dropPosition- dragPosition; int movecount_abs =Math.abs(movecount); // 取絕對值
3.是否滿足條件,滿足條件開始移動子View
if (movecount == 0) {// 說明不需要移動任何項 return; } if (dPosition !=dragPosition) { //拖動位置和最新位置不一致
4.開始移動子View位置,首先計算移動一個子View,首先計算移動子View到相鄰位置所需要移動的x,y軸的距離
float x_vlaue = ((float) getHorizontalSpacing()/ (float)itemWidth) + 1.0f; float y_vlaue = ((float) getVerticalSpacing() /(float)itemHeight) + 1.0f;
之後開始循環移動子View。
這裡又分兩種情況,分別是手勢向右拖動,子View向左移動,另外一種是分別是手勢向左拖動,子View向右移動。其中向右拖動可能會誇行,向左也一樣。在手勢移動的時候會根據是否需要移動子View的需要,首先計算出移動子View的x,y距離。
當手勢向右移動時,計算邏輯代碼如下:
holdPosition = dragPosition+ i + 1; // 移動的位置項 if (dragPosition/nColumns== holdPosition/nColumns){ // 同一行向右拖動時處理 to_x= -x_vlaue; to_y= 0; } else if (holdPosition% 3 == 0) { // 處理第一行的第一個顯示項,往上一行移動到最後 to_x= 2 * x_vlaue; to_y= -y_vlaue; } else { to_x= -x_vlaue; to_y= 0; }
代碼中判斷了移動的子View是否在同一行,分別做了不同的邏輯處理,因為這裡是寫了3列的GridView,計算的時候都是根據這個參數計算的。
當手勢向左移動時,代碼和上面差不多:
holdPosition = dragPosition- i - 1; if (dragPosition/nColumns== holdPosition/nColumns){ to_x= x_vlaue; to_y= 0; } else if ((holdPosition+ 1) % 3 == 0) { to_x= -2 * x_vlaue; to_y= y_vlaue; } else { to_x= x_vlaue; to_y= 0; }
計算出了子View需要移動的x,y距離之後,接下來就是要使用動畫移動子View了。在這裡直接創建了動畫並設置了上述步驟計算出來的x,y距離,開始移動子View:
ViewGroup moveViewGroup =(ViewGroup) getChildAt(holdPosition); Animation moveAnimation =getMoveAnimation(to_x, to_y); moveViewGroup.startAnimation(moveAnimation);
這裡是循環移動子View的過程,移動完成第一個接著會移動第二個,以此類推,所以我們看到的效果就是有幾個子View會自動移動到他們需要移動的位置。
如果最後一個子View移動完成,這時候會更新Adapter中的數據,並且更新界面,這裡主要是判斷最後一個子View動畫結束時處理上述的工作。
if (holdPosition==dropPosition){ LastAnimationID = moveAnimation.toString(); } @Override public voidonAnimationEnd(Animation animation) { // TODO Auto-generated method stub // 如果為最後個動畫結束,那執行下面的方法 if (animation.toString().equalsIgnoreCase(LastAnimationID)) { DgvAdaptermDragAdapter = (DgvAdapter) getAdapter(); mDragAdapter.exchange(startPosition,dropPosition); startPosition = dropPosition; dragPosition = dropPosition; isMoving = false; } }
在exchange()方法中,主要是根據起點位置和結束點位置對數據進行了更新,然後更新GridView顯示數據。
public void exchange(int dragPostion,int dropPostion) { holdPosition = dropPostion; DgvItemdragItem = getItem(dragPostion); if (dragPostion
這裡移動子View的過程就結束了。
3.ACTION_UP:
當停止觸摸時,這裡主要做兩件事情,一是把之前創建的一些臨時數據清除,這裡主要清除了拖動圖片的緩存。
private void stopDrag() { if (dragImageView !=null) { windowManager.removeView(dragImageView); dragImageView = null; } }
另外一個是把之前點擊隱藏的子View顯示出來。
private void onDrop(int x,int y) { int tempPostion =pointToPosition(x, y); dropPosition = tempPostion; DgvAdaptermDragAdapter = (DgvAdapter) getAdapter(); mDragAdapter.setShowDropItem(true);// 顯示剛拖動的item mDragAdapter.notifyDataSetChanged();//刷新適配器,讓對應的item顯示 }
這樣,一次移動的動作就完成了。
4.GridView列表狀態保存
這裡保存GridView的狀態是在退出的時候,獲取adapter裡面的數據,並把它存在數據庫,下次進入的時候從數據庫加載,這樣就能夠把上次移動的順序保存下來,並在下次加載的時候按上次順序顯示。
private voidsaveChannel() { DgvManager.getManage().deleteMjbhOfAll(); DgvManager.getManage().saveItems(dgvAdapter.getChannnelLst()); }
綜合上面的分析,下面給可拖動GridView的實現方式作初略的總結:
1.ACTION_DOWN:
保存了按下點的相關參數,創建了一張用戶可拖動的臨時圖片,並初始化了圖片拖動參數,最後把按下的子View隱藏了,結果就顯示了創建的圖片,視覺上就像子View彈起來顯示一樣。
2.ACTION_MOVE
圖片隨手勢移動,計算移動的參數,逐個移動子View,移動完成之後更新數據和界面。
3.ACTION_UP
清除臨時數據和顯示之前隱藏的子View。
4.退出時保存當前GridView的狀態。
下面附上一張簡單流程圖:
現在很多應用都已經涉及到 第三方登錄了,他的使用能更方便大家進入app,不用繁瑣的輸入密碼,那麼今天就來探索下 QQ 的三方登錄。首先,大家在白度上 搜 “騰
使用Web Service進行網絡編程 Android應用通常都是運行在手機平台上,手機系統的硬件資源是有限的,不管是存儲能力還是計算能力都有限,在Android系統上開
概述:單線程下載很簡單,就是開啟一個線程去下載資源再進行本地保存;多線程下載是通過RandomAccessFile(隨機文件讀寫操作類)來設置每個線程讀取文件的起始點位置
本文實例講述了Android互聯網訪問圖片並在客戶端顯示的方法。分享給大家供大家參考,具體如下:1、布局界面<RelativeLayout xmlns:androi