編輯:關於Android編程
敘述
滑動沖突可以說是日常開發中比較常見的一類問題,也是比較讓人頭疼的一類問題,尤其是在使用第三方框架的時候,兩個原本完美的控件,組合在一起之後,忽然發現整個世界都不好了。
關於滑動沖突
滑動沖突分類:
滑動沖突,總的來說就是兩類。
1.同方向滑動沖突
比如ScrollView嵌套ListView,或者是ScrollView嵌套自己
2.不同方向滑動沖突
比如ScrollView嵌套ViewPager,或者是ViewPager嵌套ScrollView,這種情況其實很典型。現在大部分應用最外層都是ViewPager+Fragment 的底部切換(比如微信)結構,這種時候,就很容易出現滑動沖突。不過ViewPager裡面無論是嵌套ListView還是ScrollView,滑動沖突是沒有的,畢竟是官方的東西,可能已經考慮到了這些,所以比較完善。
復雜一點的滑動沖突,基本上就是這兩個沖突結合的結果。
滑動沖突解決思路
滑動沖突,就其本質來說,兩個不同方向(或者是同方向)的View,其中有一個是占主導地位的,每次總是搶著去處理外界的滑動行為,這樣就導致一種很別扭的用戶體驗,明明只是橫向的滑動了一下,縱向的列表卻在垂直方向發生了動作。就是說,這個占主導地位的View,每一次都身不由己的攔截了這個滑動的動作,因此,要解決滑動沖突,就是得明確告訴這個占主導地位的View,什麼時候你該攔截,什麼時候你不應該攔截,應該由下一層的View去處理這個滑動動作。
這裡不明白的同學,可以去了解一下Android Touch事件的分發機制,這也是解決滑動沖突的核心知識。
第二種滑動沖突,解決起來是比較簡單的。這裡就結合例子說一下。
這裡,說一下背景情況。之前做下拉刷新、上拉加載更多時一直使用的是PullToRefreshView這個控件,因為很方便,不用導入三方工程。在其內部可以放置ListView,GridView及ScrollView,非常方便,用起來可謂是屢試不爽。但是直到有一天,因項目需要,在ListView頂部加了一個輪播圖控件BannerView。結果發現輪播圖滑動的時候,和縱向的下拉刷新組件沖了。
如之前所說,解決滑動沖突的關鍵,就是明確告知接收到Touch的View,是否需要攔截此次事件。
解決方法:
解決方案1,從外部攔截機制考慮
這裡,相當於是PullToRefreshView嵌套了ViewPager,那麼每次優先接收到Touch事件的必然是PullToRefreshView。這樣就清楚了,看代碼:
在PullToRefreshView中:
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
int y = (int) e.getRawY();
int x = (int) e.getRawX();
boolean resume = false;
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// 發生down事件時,記錄y坐標
mLastMotionY = y;
mLastMotionX = x;
resume = false;
break;
case MotionEvent.ACTION_MOVE:
// deltaY > 0 是向下運動,< 0是向上運動
int deltaY = y - mLastMotionY;
int deleaX = x - mLastMotionX;
if (Math.abs(deleaX) > Math.abs(deltaY)) {
resume = false;
} else {
//當前正處於滑動
if (isRefreshViewScroll(deltaY)) {
resume = true;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return resume;
}
這裡最關鍵的代碼就是這行
if (Math.abs(deleaX) > Math.abs(deltaY)) {
resume = false;
}
橫向滑動距離大於縱向時,無須攔截這次滑動事件。其實,就是這麼簡單,但前提是你必須明確了解Android Touch事件的傳遞機制,期間各個方法執行的順序及意義。
解決方案2,從內容逆向思維分析
有時候,我們不想去修改引入的第三方控件,或者說是無法修改時。就必須考慮從當前從Touch傳遞事件中最後的那個View逆向考慮。首先,由Android中View的Touch事件傳遞機制,我們知道Touch事件,首先必然由最外層View攔截,如果無法更改這個最外層View,那麼是不是就沒轍了呢?其實不然,Android這麼高大上的系統必然考慮到了這個問題,好了廢話不說,先看代碼
private BannerView carouselView;
private Context mContext;
private PullToRefreshView refreshView;
.........
refreshView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
carouselView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
carouselView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
carouselView.getParent().requestDisallowInterceptTouchEvent(true);
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int deltaY = y - lastY;
int deltaX = x - lastX;
if (Math.abs(deltaX) < Math.abs(deltaY)) {
carouselView.getParent().requestDisallowInterceptTouchEvent(false);
} else {
carouselView.getParent().requestDisallowInterceptTouchEvent(true);
}
default:
break;
}
return false;
}
});
說一下這個方法
public abstract void requestDisallowInterceptTouchEvent (boolean disallowIntercept)
子View如果不希望其父View攔截Touch事件時,可調用此方法。當disallowIntercept這個參數為true時,父View將不攔截。
好了,言歸正傳。這裡攔截直接也很明確,在carouselView的onTouch方法中每次進入就設定父View不攔截此次事件,然後在MOTION_MOVE時候,根據滑動的距離判斷再決定是父View是否有權利攔截Touch事件(即滑動行為)。
ViewPager禁止滑動
或者我們干脆就把滑動給禁止了:
public class CustomViewPager extends ViewPager {
private boolean isPagingEnabled = true;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}
public void setPagingEnabled(boolean b) {
this.isPagingEnabled = b;
}}
Android中子線程真的不能更新UI嗎?
Android的UI訪問是沒有加鎖的,這樣在多個線程訪問UI是不安全的。所以Android中規定只能在UI線程中訪問UI。但是有沒有極端的情況?使得我們在子線程中訪問UI
詳解Android 進程間通信的幾種實現方式
一、概述由於應用程序之間不能共享內存。在不同應用程序之間交互數據(跨進程通訊),在Android SDK中提供了4種用於跨進程通訊的方式。這4種方式正好對應於androi
android 記事本程序源碼
應用實現密碼登陸,記事本內容可增刪改除等操作,用listview顯示每次保存的記事內容,實現了記事本的基本功能。代碼都有詳細注解。1、代碼的目錄密碼登陸使用的是share
小米手環2和唯樂now2哪個好 小米手環2對比唯樂NOW2手環怎麼樣
小米手環2和唯樂now2哪個好?小米手環2准備開放購買了,小編了解到,還有一款唯樂now2可以選擇,如果買不到小米手環2的網友,也可以考慮唯樂手環,那麼小米