一、前言
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.如果中途事件被消耗,则不会继续传递。