1、事件(MotionEvent)
事件被ViewGroup拦截或者子View的onTouchEvent都返回false,事件由ViewGroup处理
子View的onTouchEvent都返回false,则父View的onTouchEvent被调用,都不处理则由Activity的onTouchEvent处理
先传递ACTION_DOWN 如果处理,再传递ACTION_MOVE和ACTION_MOVE
ACTION_CANCEL //取消事件 由程序产生
OnTouch时 GroupView调用顺序:
dispatchTouchEvent //事件分发 返回true处理结束,返false不处理 没必要重写
onInterceptTouchEvent //事件的拦截 默认返false
onTouchEvent //事件处理 子向父传 View中默认返true,既处理事件
onInterceptTouchEvent和onTouchEvent决定事件的传递方向
底层View一般是一个ViewGroup 默认不拦截点击事件
onInterceptTouchEvent(ViewGroup才有)
返回true ViewGroup处理事件
如果 onTouchListener 被设置调用onTouch(滑动)
否自 onTouchEvent 被调用
二者都提供 onTouch(优先级高)会屏蔽onTouchEvent
onClick基于onTouchEvent实现,在onTouchEvent中如果设置OnClickListener 则调用onClick
返回false 不拦截
传给子View -> 子View(如果是ViewGroup)的 dispatchTouchEvent
View对事件处理
设了OnTouchListener 调用onTouch
否则调onTouchEventonClick在其中通过performClick触发
当前界面底层容器 DecorView,既setContentView设置的View的父容器,activity.getWindow.getDecorView()可获取
DecorView 继承自FrameLayout 是根View的最底层
event.getY //屏幕上的位置
2、示例
这是一个ScrollView嵌套使用的例子,参考自http://blog.sina.com.cn/s/blog_6271df6f0101ap4w.html
MainActivity.java
public class MainActivity extends Activity {
ScrollView scrollView;//外层ScrollView
InnerScrollView innerScrollView;//内从ScrollView
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scrollView = (ScrollView)findViewById(R.id.scrollView1);
innerScrollView = (InnerScrollView)findViewById(R.id.scrollView2);
//内层的ScrollView需要向外层的ScrollView传递滑动事件
innerScrollView.parentScrollView = scrollView;
}
}
public class InnerScrollView extends ScrollView {
/**外层ScrollView*/
public ScrollView parentScrollView;
/**当前屏幕Y轴上的位置*/
int currentY;
public InnerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (parentScrollView == null) {
return super.onInterceptTouchEvent(ev);
} else {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
currentY = (int)ev.getY();
//requestDisallowInterceptTouchEvent 是ViewGroup类中的一个公用方法,子类可通过此方法告诉父类是否拦截点击事件
requestDisallowInterceptTouchEvent(true);//此处不做拦截会影响灵敏度
return super.onInterceptTouchEvent(ev);
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
parentScrollView.requestDisallowInterceptTouchEvent(false);//此处不回复拦截会影响灵敏度
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
View child = getChildAt(0);
if (parentScrollView != null) {
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
int height = child.getMeasuredHeight();//获取InnerScrollView中嵌套的线性布局的高度
int self_height = getMeasuredHeight();//获取InnerScrollView自身的高度
height = height - self_height;
int scrollY = getScrollY();
int y = (int)ev.getY();
if (currentY < y) { // 手指向下滑动
if (scrollY <= 0) {
// 如果向下滑动到头,就把滚动交给父Scrollview onTouchEvent要返回false
parentScrollView.requestDisallowInterceptTouchEvent(false);
return false;
} else {
parentScrollView.requestDisallowInterceptTouchEvent(true);
}
} else if (currentY > y) {
if (scrollY >= height) {
// 如果向上滑动到头,就把滚动交给父Scrollview
parentScrollView.requestDisallowInterceptTouchEvent(false);
return false;
} else {
parentScrollView.requestDisallowInterceptTouchEvent(true);
}
}
currentY = y;
}
}
return super.onTouchEvent(ev);
}
}
参考代码: http://download.csdn.net/detail/duduhali/9425834