接着上篇Android學習系列(10)--App列表之拖拽ListView(上)我們繼續實現ListView的拖拽效果。
7.重寫onTouchEvent()方法。
在這個方法中我們主要是處理拖動和放下。
拖動是選中項的影像隨着手指滑動;放下是在拖動結束的時候交換數據。
方法的整體結構如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 觸摸事件 */ @Override public
boolean onTouchEvent(MotionEvent ev) { //如果dragmageView爲空,說明攔截事件中已經判定僅僅是點擊,不是拖動,返回 //如果點擊的是無效位置,返回,需要重新判斷 if (dragImageView!= null &&dragPosition!=INVALID_POSITION){ int
action = ev.getAction(); switch (action){ case
MotionEvent.ACTION_UP: int
upY = ( int )ev.getY(); //釋放拖動影像 stopDrag(); //放下後,判斷位置,實現相應的位置刪除和插入 onDrop(upY); break ; case
MotionEvent.ACTION_MOVE: int
moveY = ( int )ev.getY(); //拖動影像 onDrag(moveY); break ; default : break ; } return
true ; } //這個返回值能夠實現selected的選中效果,如果返回true則無選中效果 return
super .onTouchEvent(ev); } |
8.拖動影像。
拖動的時候,我們調用了onDrag(int y)方法,主要做的事情是,讓選中項的影像隨這手指滑動起來。如下:
1
2
3
4
5
6
7
8
|
if (dragImageView!= null ){ //設置一點點的透明度 windowParams.alpha =
0 .8f; //更新y座標位置 windowParams.y = y - dragPoint + dragOffset; //更新界面 windowManager.updateViewLayout(dragImageView, windowParams); } |
當數據集合很大的時候,還需要在拖動到上部區域或者下部區域的時候滾動列表,使用ListView自帶的方法setSelectionFromTop()。
一個可以滾動的拖拽列表雛形就出來了,最終onDrag()方法代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 拖動執行,在Move方法中執行 * @param y */ public
void onDrag( int
y){ if (dragImageView!= null ){ windowParams.alpha =
0 .8f; windowParams.y = y - dragPoint + dragOffset; windowManager.updateViewLayout(dragImageView, windowParams); } //爲了避免滑動到分割線的時候,返回-1的問題 int
tempPosition = pointToPosition( 0 , y); if (tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //滾動 int
scrollHeight = 0 ; if (y<upScrollBounce){ scrollHeight =
8 ; //定義向上滾動8個像素,如果可以向上滾動的話 } else
if (y>downScrollBounce){ scrollHeight = - 8 ; //定義向下滾動8個像素,,如果可以向上滾動的話 } if (scrollHeight!= 0 ){ //真正滾動的方法setSelectionFromTop() setSelectionFromTop(dragPosition, getChildAt(dragPosition-getFirstVisiblePosition()).getTop()+scrollHeight); } } |
拖動的效果如下:
9.放下影像,數據更新。
上面實現了拖動的效果,放下影像後:
1)我們要獲取放下的位置是數據集合的哪一項;
2)在放下位置項插入拖動數據,並刪除拖動數據原位置項
這些處理寫在了onDrop()方法中,在ACTION_UP動作中執行,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/** * 拖動放下的時候 * @param y */ public
void onDrop( int
y){ //獲取放下位置在數據集合中position //定義臨時位置變量爲了避免滑動到分割線的時候,返回-1的問題,如果爲-1,則不修改dragPosition的值,急需執行,達到跳過無效位置的效果 int
tempPosition = pointToPosition( 0 , y); if (tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //超出邊界處理 if (y<getChildAt( 0 ).getTop()){ //超出上邊界,設爲最小值位置0 dragPosition =
0 ; } else
if (y>getChildAt(getChildCount()- 1 ).getBottom()){ //超出下邊界,設爲最大值位置,注意哦,如果大於可視界面中最大的View的底部則是越下界,所以判斷中用getChildCount()方法 //但是最後一項在數據集合中的position是getAdapter().getCount()-1,這點要區分清除 dragPosition = getAdapter().getCount()- 1 ; } //數據更新 if (dragPosition> 0 &&dragPosition<getAdapter().getCount()){ @SuppressWarnings ( "unchecked" ) ArrayAdapter<String> adapter = (ArrayAdapter<String>)getAdapter(); String dragItem = adapter.getItem(dragSrcPosition); //刪除原位置數據項 adapter.remove(dragItem); //在新位置插入拖動項 adapter.insert(dragItem, dragPosition); } } |
我處理了一下(在dapter的方法中定義getList()方法得到adpter中List<String>,使用toString()方法連接起來),把adapter的結果輸出來看看:
至於數據的詳細處理或者保存,不是本文拖拽的內容,只要抓住adapter集合分析應該很容易的。
三、拓展
10.分組拖拽拓展。
前面我們一直在數據源中添加了分組標籤A組,B組的,下面我們就把數據分成A組,B組,更詳細內容可參考
Android學習系列(9)--App列表之分組ListView。
1)定義分組標籤樣式佈局drag_list_item_tag.xml。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<? xml
version = "1.0"
encoding = "utf-8" ?> android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:background = "#555555" android:padding = "5dip" android:paddingLeft = "10dip" > <!--文本框的ID保持不變--> < TextView android:id = "@+id/drag_list_item_text" android:layout_width = "wrap_content" android:layout_height = "20dip" android:textColor = "#ffffff" android:gravity = "center_vertical" /> <!--去除來右邊拖拽圖像,分組標籤是不能隨意拖動的--> </ LinearLayout > |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Override public
View getView( int
position, View convertView, ViewGroup parent) { View view = convertView; if (groupKey.contains(getItem(position))){ //如果是分組標籤,就加載分組標籤的佈局文件,兩個佈局文件顯示效果不同 view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item_tag,
null ); } else { //如果是正常數據項標籤,就加在正常數據項的佈局文件 view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item,
null ); } TextView textView = (TextView)view.findViewById(R.id.drag_list_item_text); textView.setText(getItem(position)); return
view; } |
3)禁用分組標籤項的響應事件,在DragListAapter中重寫方法isEnable()。
剛好因爲在分組標籤中去掉了拖拽圖像,所以點擊在分組標籤中的話,dragImageView爲空,不會有被拖動的效果了,這就是前面說的順手的一個妙用了。
1
2
3
4
5
6
7
8
|
@Override public
boolean isEnabled( int
position) { if (groupKey.contains(getItem(position))){ //如果是分組標籤,返回false,不能選中,不能點擊 return
false ; } return
super .isEnabled(position); } |
1
2
3
4
5
6
7
8
|
//上邊界改爲1 if (y<getChildAt( 1 ).getTop()){ //超出上邊界 dragPosition =
1 ; } else
if (y>getChildAt(getChildCount()- 1 ).getBottom()){ //超出下邊界 dragPosition = getAdapter().getCount()- 1 ; } |
至此,拖拽ListView的實現結束了。
如果您發現有什麼bug,聯繫我。
難得的上傳一下代碼,沒找到博客園上傳文件的地方,我放到了github上,下載地址是: https://github.com/fjtianxia/qianxudetianxia。