問題:我在ScrollView裏面嵌套了一個ScrollView,嵌套的ScrollView超出了屏幕顯示部分,需要向下滑動才能看到,當滑動下去找到嵌套的ScrollView時,滑動時並不能觸發它的onTouch()事件。
Android的Touch傳遞機制,這裏不詳細介紹了,有想了解的,推薦http://blog.csdn.net/chunqiuwei/article/details/41084921,和http://www.infoq.com/cn/articles/android-event-delivery-mechanism/ 這兩篇寫得都不錯,可以借鑑一下。
解決思路:
1. 先是參考的http://mengsina.iteye.com/blog/1707464這一篇文章,主要利用了在onTouch()事件裏面寫v.getParent().requestDisallowInterceptTouchEvent(true); 這種方法,讓父ScrollView不攔截Touch事件,自己來處理。
親自實驗了這個方法,當嵌套的ScrollView不超出屏幕時是可以用的,可是當嵌套的ScrollView超出屏幕時,就不可以了。
代碼如下,當touch子ScrollView時,打印出”觸摸了第2個ScrollView”,然而並沒有成功,結果在後面,全都是打印的”觸摸了第1個ScrollView”:
MainActivity.java->onCreate():
//父ScrollView
svParent = (ScrollView) findViewById(R.id.sv_parent);
svParent.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
ViewParent parent = findViewById(R.id.sv_child).getParent();
parent.requestDisallowInterceptTouchEvent(false); //允許父類截斷
System.out.println("觸摸了第1個ScrollView");
return false;
}
});
//子ScrollView
svChild = (ScrollView) findViewById(R.id.sv_child);
svChild.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
ViewParent parent1 = v.getParent();
parent1.requestDisallowInterceptTouchEvent(true); //不允許父類截斷
System.out.println("觸摸了第2個ScrollView");
return false;
}
});
結果截圖:
從這個結果來看,Touch事件,沒有傳遞到嵌套的ScrollView上來,應該是被上層的ViewGroup截獲,或者是傳下去被下面的View消費掉了,沒再傳上來。
2.接下來,就是想讓這個嵌套的ScrollView截獲傳遞過來的Touch事件,不再分發下去了。所以想到重寫ScrollView的onInterceptTouchEvent(),讓它返回true,讓這個嵌套的ScrollView截獲這個Touch事件(注意:onInterceptTouchEvent()返回true,表示截獲這個Touch事件;返回false,表示不搭理這個Touch事件)。
自定義ScrollView CustomScrollView.java:
package com.tudou.scrollviewnested;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
/**
* Created by Administrator on 2016-08-14.
*/
public class CustomScrollView extends ScrollView {
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("第2個ScrollView:dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println( "第2個ScrollView: onInterceptTouchEvent: ");
// return super.onInterceptTouchEvent(ev);
boolean flag = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
flag = super.onInterceptTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
flag = true;
break;
}
return flag;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
System.out.println( "第2個ScrollView: onTouchEvent: ");
return super.onTouchEvent(ev);
}
}
在上面的代碼裏面可以看到,onInterceptTouchEvent()函數,我讓它直接返回了true。再看一下結果,看看調用順序哈。
結果截圖:
從結果上可以看出這幾個函數的調用順序:
1. 是CustomScrollView裏面的dispatchTouchEvent()
2. 是CustomScrollView裏面的onInterceptTouchEvent()
3. 是MainActivity裏面的svChild.setOnTouchListener->onTouch()事件
4. 是CustomScrollView裏面的onTouchEvent()
^_^ OK~~~~~~~