1. 程式人生 > >我的第一個開源控制元件-DragGridView

我的第一個開源控制元件-DragGridView

我的第一個開源控制元件出爐了,希望各個小夥伴給個star,支援下。專案地址

1. 前言

由於專案需要,要做一個類似騰訊視訊,頻道管理,拖拽排序的效果。這個控制元件是在原地址 之上改造出來的。先看下效果圖。
 1.0版本的效果圖
由於我電腦是ubuntu,沒法弄gif,等星期一到了公司上gif吧,不過,github上有apk,可以弄下來看看,
這裡寫圖片描述

2. 實現思路

2.1 如何響應長按事件

我們雖然可以給view設定監聽器,但是我們需要頻繁的呼叫GridVIew的一些方法,顯然,那樣做是不合適的。於是,我們在onInterceptTouchEvent中設定長按和短按的監聽。

2.2 響應長按之後幹什麼

在響應長按事件之後,我們通過windowmanager在我們長按處新增一個view.新增view的程式碼如下。

windowParams = new WindowManager.LayoutParams();
        windowParams.gravity = Gravity.TOP | Gravity.LEFT;
        windowParams.x = x - win_view_x;
        windowParams.y = y - win_view_y;
        windowParams.width = (int) (dragScale * dragBitmap.getWidth
());// 放大dragScale倍,可以設定拖動後的倍數 windowParams.height = (int) (dragScale * dragBitmap.getHeight());// 放大dragScale倍,可以設定拖動後的倍數 this.windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams
.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; this.windowParams.format = PixelFormat.TRANSLUCENT; this.windowParams.windowAnimations = 0; ImageView iv = new ImageView(getContext()); iv.setImageBitmap(dragBitmap); windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window" windowManager.addView(iv, windowParams);

2.3 移動的過程怎麼處理

移動的過程中我們需要處理2件事,更改view的位置,動畫。
先說更改view的位置。程式碼如下

windowParams.alpha = 1.f;
            windowParams.x = rawx - win_view_x;
            windowParams.y = rawy - win_view_y;
            windowManager.updateViewLayout(dragImageView, windowParams);

我們只需要修改params的x,y,並且update即可。再說動畫。

  • 計算當前所在的position | pointToPosition(x, y);
  • 計算應該移動的數量 | 當前-移動那一塊
movecount = endPosition - dragPosition;
  • 根據大小計算移動的方向和距離
for (int i = 0; i < movecount_abs; i++) {
                    to_x = x_vlaue;
                    to_y = y_vlaue;
                    //像左
                    if (movecount > 0) {
                        // 判斷是不是同一行的
                        holdPosition = dragPosition + i + 1;
                        if (dragPosition / mColumns == holdPosition / mColumns) {
                            to_x = -x_vlaue;
                            to_y = 0;
                        } else if (holdPosition % 4 == 0) {
                            to_x = 3 * x_vlaue;
                            to_y = -y_vlaue;
                        } else {
                            to_x = -x_vlaue;
                            to_y = 0;
                        }
                    } else {
                        //向右,下移到上,右移到左
                        holdPosition = dragPosition - i - 1;
                        if (dragPosition / mColumns == holdPosition / mColumns) {
                            to_x = x_vlaue;
                            to_y = 0;
                        } else if ((holdPosition + 1) % 4 == 0) {
                            to_x = -3 * x_vlaue;
                            to_y = y_vlaue;
                        } else {
                            to_x = x_vlaue;
                            to_y = 0;
                        }
                    }
  • 在動畫結束的時候更新資料來源 
    我們需要做的大概就是上面幾部。那麼,現在我們移動完了。

2.4 up事件的處理

由於這樣的控制元件,百分之90可能會有資料聯動,所以,我們需要在Up事件中回撥通知其他的adapter資料來源變化(注意,up事件很可能發生在多次動畫之後)。

((BaseDragAdapter)getAdapter()).dragEnd();
                    requestDisallowInterceptTouchEvent(false);

恩,大概就這麼多了。具體的大家看程式碼吧。

3. 結語

這個控制元件,我已經用在了開發當中,雖然,這個控制元件還存在一些問題,如adapter不能使用convertView and holder來優化等等。