我的第一個開源控制元件-DragGridView
阿新 • • 發佈:2019-02-08
我的第一個開源控制元件出爐了,希望各個小夥伴給個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來優化等等。