一、前言
Android的Touch事件属于一个很基本的Android知识点,在面试中经常会被问到,在实际的代码开发中偶然也会碰到,特别是在自定义控件的时候,需要处理自定义控件与底层布局的冲突。因此很有必要总结一下Android Touch事件的传递过程。
二、Android Touch事件的相关介绍
Touch事件的分发,拦截和处理函数
public boolean dispachTouchEvent(MotionEvent ev) 事件的分发函数
public boolean onInterceptTouchEvent(MotionEvent ev)事件的函数
public boolean onTouchEvent(MotionEvent ev) 事件的处理函数
这三个方法在ViewGroup,View,Activity中,具体的情况如下表:
事件函数 |
ViewGroup |
View |
Activity |
dispachTouchEvent |
有 |
有 |
有 |
onInterceptTouchEvent |
有 |
无 |
无 |
onTouchEvent |
有 |
有 |
有 |
三、事件的处理流程
先上代码,参考代码如下,一个MainActivity.java, 两个自定义控件MyLayoutFirst.java,MyLayoutSecond.java。在MainActivity的布局文件中,MyLayoutSecond处于最上层,MyLayoutSecond包含MyLayoutFirst。
3.1 参考运行代码
1.MainActivity.java
|
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("yzy", "MainActivity->dispatchTouchEvent->" + MyUtils.getActionName(ev));
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("yzy", "MainActivity->onTouchEvent->" + MyUtils.getActionName(event));
return super.onTouchEvent(event);
}
}
|
2.MyLayoutFirst.java
|
public class MyLayoutFirst extends LinearLayout {
private static final String TAG = "MyLayoutFirst";
public MyLayoutFirst(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.w("yzy", "MyLayoutFirst->onInterceptTouchEvent->" + MyUtils.getActionName(ev));
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("yzy", "MyLayoutFirst->onTouchEvent->" + MyUtils.getActionName(event));
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("yzy", "MyLayoutFirst->dispatchTouchEvent->" + MyUtils.getActionName(ev));
return super.dispatchTouchEvent(ev);
}
}
|
3. MyLayoutSecond.java
|
public class MyLayoutSecond extends LinearLayout {
private static final String TAG = "MyLayoutSecond";
public MyLayoutSecond(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("yzy", "MyLayoutSecond->MyLayoutSecond->" + MyUtils.getActionName(event));
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.w("yzy", "MyLayoutSecond->onInterceptTouchEvent->" + MyUtils.getActionName(ev));
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("yzy", "MyLayoutSecond->dispatchTouchEvent->" + MyUtils.getActionName(ev));
return super.dispatchTouchEvent(ev);
}
}
|
4.MyUtils.java
|
public class MyUtils
{
private static final String TAG = "MyUtils";
public static String getActionName(MotionEvent event)
{
String name="";
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
name="ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
name="ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
name="ACTION_UP";
break;
}
return name;
}
}
|
5.布局XML文件
|
<RelativeLayout 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">
<com.example.moxie.testapplication.MyLayoutFirst
android:id="@+id/layout_first"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000">
<com.example.moxie.testapplication.MyLayoutSecond
android:id="@+id/layout_second"
android:layout_width="320dip"
android:layout_height="120dip"
android:layout_gravity="center"
android:background="#0000FF">
</com.example.moxie.testapplication.MyLayoutSecond>
</com.example.moxie.testapplication.MyLayoutFirst>
</RelativeLayout>
|
3.2 Touch事件流程
经过上面测试代码运行可以总结Touch事件的传递流程如下:
事件处理流程为:Activity--(分发)-->父控件--(分发)-->父控件--(拦截)-->子控件-->(分发)-->子控件-->(拦截)-->子控件-->(处理)-->父控件-->(处理)-->Activity(处理)
1.事件会由底层往上层进行分发和拦截;
2.如果1中没有进行处理,则在上层子空间中执行消耗事件的操作,没有则继续传递到父控件或底层的Activity。
3.如果中途事件被消耗,则不会继续传递。