背景
項目中要實現控件的滑動監聽其實還是挺常見的,這裏就簡單的做一下記錄。
實現的方式也有好幾種,我這裏就只實現一種:自己覺得對手勢滑動的判斷比較準確且穩定的一個方式。
實現
手勢監聽器的聲明和創建
- 聲明如下:
private GestureDetector detector = null;// 聲明一個手勢監聽器
- 創建如下:
// 創建 GestureDetector 對象,並重寫相關方法
detector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.e("TAG", "onScroll");
Log.e("TAG", "onScroll distanceX = " + distanceX);
Log.e("TAG", "onScroll distanceY = " + distanceY);
//distanceY > 0 表示上滑了
if (distanceY > 0){
}
// distanceY > 0 表示下滑了
if (distanceY < 0){
}
// 表示左滑了
if(distanceX > 0){
Log.e("TAG", "表示左滑了");
}
// 表示右滑了
if(distanceX < 0){
Log.e("TAG", "表示右滑了");
}
return true;// 事件被消費了,不會繼續傳遞
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// 需要用戶手指觸摸屏幕後的一次稍微快速的滑動並且手指擡起後纔會回調該方法
// 如果速度較慢,那麼該方法不會回調(可能也正好解釋了 fling:猛動 這個詞的意思吧)
Log.e("TAG", "onFling");
return true;// 事件被消費了,不會繼續傳遞
}
});
上面創建的代碼中,我在重寫的方法添加了一些關鍵註釋,建議同學們都瞭解一下,對加深自己的理解有作用。
對重寫的相關方法 onScroll() 說明
首先看下該方法的源碼:
/**
* Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
* current move {@link MotionEvent}. The distance in x and y is also supplied for
* convenience.
*
* @param e1 The first down motion event that started the scrolling.
* @param e2 The move motion event that triggered the current onScroll.
* @param distanceX The distance along the X axis that has been scrolled since the last
* call to onScroll. This is NOT the distance between {@code e1}
* and {@code e2}.
* @param distanceY The distance along the Y axis that has been scrolled since the last
* call to onScroll. This is NOT the distance between {@code e1}
* and {@code e2}.
* @return true if the event is consumed, else false
*/
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
源碼講了:當你觸屏屏幕並開始滑動時就會觸發這個方法,相關參數的解釋也相對簡單易懂
這裏根據 distanceX
和 distanceY
的值大小來判斷手勢滑動的一個具體方向
distanceX
參數用來判斷左右方向的一個滑動,當該值大於 0 表示手勢左滑,當該值小於 0 表示手勢右滑distanceY
參數用來判斷上下方向的一個滑動,當該值大於 0 表示手勢上滑,當該值小於 0 表示手勢下滑
不過我在 onScroll()
方法裏面的判斷只是比較粗略的(只用到了其中一個參數來做判斷),如果同學們想很準確的表示左右滑動或者上下滑動,就需要用到兩個參數(通過對參數進行值的約束來達到準確的判斷)
手勢監聽器接管View的觸屏事件
這裏因爲一些佈局或者是控件的頂層父類其實都是 View,所以我這裏拿 View 來說明。
既然 View 有觸屏事件,所以肯定要給 View 設置觸摸事件,如下:
// 顯示設置一下控件可點擊
linear.setClickable(true);
// 線性佈局設置觸摸監聽事件
linear.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
// 手勢監聽器分析給定view(這裏是linearLayout佈局)的觸屏事件
// 相當於由手勢監聽器來接管這個view的觸屏事件
return detector.onTouchEvent(event);
}
});
在觸摸事件監聽的代碼中返回 detector.onTouchEvent(event);
表示讓手勢監聽器來消費這個觸屏事件,就相當於由手勢監聽器接管了該事件。
注意:記得給 View
設置一下可點擊屬性爲 true
,讓手勢監聽器對象能成功的消費這個 View
的觸屏事件
驗證結果
同學們只需要在判斷的地方添加打印 log
日誌代碼,然後運行一下項目,自己手勢滑動一下看看日誌輸出即可。
如下圖示:
這裏不直觀,我給出一個 demo
中的 gif動圖
演示,是手勢上下滑動控制月亮
亮度動畫
的漸變,如下:
- 提供
demo apk
下載鏈接
- 提取碼
xv8c
感興趣的同學可以去下載安裝體驗一下。
技術永不眠,我們下期見!