Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 可拖動GridView的實現,類似支付寶界面

可拖動GridView的實現,類似支付寶界面

編輯:關於Android編程

1.概述

之前實現過一個仿支付寶界面的代碼,可拖動網格視圖。其實實現的原理網上都可以找到,我也是參考網上實現的方法,實現了自己需要的界面。並對實現的原理和方法進行了分析,現在進行總結,放太久都快忘記自己做過這回事了。原理和實現網上大部分地方都可以找到,我是根據自己的理解進行分析的,現在對之前的工作進行總結,了解實現的基本過程和方法。GridView拖動的源碼來源於網上,根據需求修改成了需要的效果,下面簡單說明下實現過程。

在說明實現之前,先上一張總體的界面效果圖:

\

 

為了更好說明程序種各個變量的意義,我把界面增加了一個縮進,效果如下

\

2.可拖動GridView實現原理

實現的原理並不復雜,通過GridView提供的基本方法、一些動畫的基本操作以及移動時邏輯的判斷和處理即可實現,為了更好說明代碼實現的原理,對代碼中使用的一些變量進行說明,參考下面這張圖,時間倉促,隨便畫的,是想更好說明問題。。

\

 

從上圖可以看出相關參數的實際意義,下面將從ACTION_DOWN,ACTION_MOVE,ACTION_UP這三個常用的action分析拖動GridView的基本流程。

 

3.實現過程

1.ACTION_DOWN

在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隨按下動作彈起來了一樣。

2.ACTION_MOVE:

在移動手勢的時候,主要完成兩方面的事情,一是手指移動時點擊的圖標會隨手勢移動,二是當移動滿足一定條件是,子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());
}

 

4.總結

綜合上面的分析,下面給可拖動GridView的實現方式作初略的總結:

1.ACTION_DOWN:

保存了按下點的相關參數,創建了一張用戶可拖動的臨時圖片,並初始化了圖片拖動參數,最後把按下的子View隱藏了,結果就顯示了創建的圖片,視覺上就像子View彈起來顯示一樣。

2.ACTION_MOVE

圖片隨手勢移動,計算移動的參數,逐個移動子View,移動完成之後更新數據和界面。

3.ACTION_UP

清除臨時數據和顯示之前隱藏的子View。

4.退出時保存當前GridView的狀態。

下面附上一張簡單流程圖:

 

\


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved