从此妈妈再也不用担心我的View冲突了
一个APP的界面中为了达到各种炫酷的效果,舒适的体验总是多个View进行嵌套,但有的时候我们要去点击不同的View,但这时候Android系统疯了,他们都堆在一起,鬼知道你要点哪个View,所以必须有一套完善的分发机制来搞定这个问题,而我们只有了解这套分发机制,只要重写固定的几个分发,冲突也就可以迎刃而解。
只有3个方法
没错整个Android的分发机制,只有3个方法,分别是:
public boolean dispatchTouchEvent(MotionEvent ev)
public boolean onInterceptTouchEvent(MotionEvent ev)
public boolean onTouchEvent(MotionEvent ev)
这三者间的关系嘛,就好像dispatchTouchEvent是刘备,onInterceptTouchEvent是诸葛亮,onTouchEvent是关羽,前方有个郡被魏国攻击了,只要关于蜀国刘备就得处理,所以dispatchTouchEvent肯定会调用,然后刘备就会问诸葛亮(前期刘备一般是听诸葛亮的),如果诸葛亮同意打,那刘备就派关羽出战,关羽之勇自然就没那个太守什么事了,如果不同意,那就让被攻击的那个郡的太守自主防御,至于它如何调兵遣将就是它的事了,不过肯定的是它肯定也会有军师和战将。被攻击的那个郡的太守自主防御成功就没事咯,如果失败了,那还得关羽出战了。而且这个时候,刘备再也不会把防御任务交给那个郡了。
故事听晕了吧
其实质就是dispathchTouchEvent负责管理分发,onInterceptTouchEvent负责判断当前view是否拦截,如果拦截交给OnTouchEvent处理,如果不拦截交给子View的dispathchTouchEvent处理,OnTouchEvent负责处理拦截后要执行的事件。
看下实验就明白了
首先需要自定义个ViewGroup,我这里采用最简单的继承LinearLayout
package cn.edu.nuc.myviewtext;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by lenovo on 2016/1/10.
*/
public class MyLinearLayout extends LinearLayout {
public static final String TAG="MyLinearLayout";
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d(TAG,"调用dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d(TAG,"调用onInterceptTouchEvent");
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG,"调用MyLinearLayout的onTouchEvent");
return super.onTouchEvent(event);
}
}
然后是自定义View,我这里采用继承TextView
package cn.edu.nuc.myviewtext;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* Created by lenovo on 2016/1/10.
*/
public class MyView extends TextView {
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(MyLinearLayout.TAG,"调用MyView的onTouchEvent");
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d(MyLinearLayout.TAG,"调用MyView的dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
}
Activity更简单
package cn.edu.nuc.myviewtext;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<cn.edu.nuc.myviewtext.MyLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cn.edu.nuc.myviewtext.MainActivity">
<cn.edu.nuc.myviewtext.MyView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="50dp"/>
</cn.edu.nuc.myviewtext.MyLinearLayout>
需要做的实验有:将MyLinearLayout的onInterceptTouchEvent方法设置为false,然后分别将MyView的onTouchEvent设置为true和false,MyView的onTouchEvent设置为flase的时候然后再将MyLinearLayout的onTouchEvent设置为true和false查看有什么区别。
然后将MyLinearLayout的onInterceptTouchEvent设置为true,然后将MyLinearLayout的onTouchEvent分别设置为true和false查看有什么区别。
一共是6个实验,相信大家看到6个实验的结果,就会对View冲突全部理解,而且注意测试的时候不要用点击,要用滑动测试,会有不同的效果
补充
重写View和ViewGroup的时候,如果要在xml文件中使用的话,必须要重写2个参数的构造函数。