實作這麼一個效果,一個布局中有一個View,那個View會随着我們手指的拖動而滑動,這種效果該如何實作?
我們第一反應應該是自定義一個DragView類繼承View,然後重寫onTouchEvent()方法,然後根據我們手指滑動的軌迹來調整DragView的顯示位置。沒錯,就是這個思路,下面我們來實作一下。
1 private float lastX;
2 private float lastY;
3 @Override
4 public boolean onTouchEvent(MotionEvent event) {
5
6 switch (event.getAction()) {
7 case MotionEvent.ACTION_DOWN:
8 lastX = event.getRawX();
9 lastY = event.getRawY();
10 break;
11 case MotionEvent.ACTION_UP:
12 break;
13 case MotionEvent.ACTION_MOVE:
14 float dx = event.getRawX() - lastX;
15 float dy = event.getRawY() - lastY;
16 //控制View移動的方法
17 move(dx, dy);
18 lastX = event.getRawX();
19 lastY = event.getRawY();
20
21 break;
22
23 }
24
25 return true;
26
27 }
注意這裡getRawX()和getX()的差別,Raw是“未經處理”的意思,getRawX()擷取的是觸點相對于整個螢幕的坐标,以螢幕左上角為原點。而getX()是經過處理後的坐标,aa也就是觸點相對于目前View的坐标,是以View的左上角為坐标原點。
很簡短的一段邏輯,記錄手指每次移動的相對距離,然後調用move方法來移動控件,最後 return true代表這個控件消費了事件,如果不了解的同學需要先看這篇文章Android事件分發機制,來了解onTouchEvent是如何被調用的,然後再往下看。
接下來就是move方法的實作,我們實作View滑動的思路有3種:第1種就是改變View的屬性,類似于屬性動畫的原理,可以看看這篇文章:Android動畫原理;第2種是改變View的布局參數來實作滑動;第3種是使用View的scrollBy方法來實作滑動,我們先來看第一種的實作。
1 private void move(float dx, float dy) {
2 setTranslationX(getTranslationX()+dx);
3 setTranslationY(getTranslationY()+dy);
4 }
這裡是依靠重新設定View的TranslationX屬性值來實作滑動,我們看看效果。
效果還不錯,我們試試另一種方法,就是改變布局來實作滑動
1 private void move(float dx, float dy) {
2 setLeft((int) (getLeft()+dx));
3 setRight((int) (getRight()+dx));
4 setTop((int) (getTop()+dy));
5 setBottom((int) (getBottom()+dy));
6 }
效果和上圖一樣。最後我們看用scrollBy()來實作的滑動
1 private void move(float dx, float dy) {
2 //這裡要用負數,因為滑動的是布局的邊框,正好和内容的滑動方向相反
3 int x = (int) -dx;
4 int y = (int) -dy;
5 this.scrollBy(x, y);
6 }
結果居然沒有滑動效果!後來才知道,原來這個是滑動View的内容,而不是View本身。是以我們在View上畫個小點就能看出來他是怎麼工作的了。
果然,隻有小點在随着滑動,也就是View的内容。是以我們有内容滑動的時候可以用srcollBy或者srcollTo,如果View本身要滑動上面兩種方法是很好的選擇。
代碼位址:https://github.com/linghu88/mScrollview