没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
试读
11页
本文以实例形式讲述了Android Touch事件分发过程,对于深入理解与掌握Android程序设计有很大的帮助作用。具体分析如下: 首先,从一个简单示例入手: 先看一个示例如下图所示: 布局文件 : <FrameLayout xmlns:android=http://schemas.android.com/apk/res/android xmlns:tools=http://schemas.android.com/tools android:id=@+id/container android:layout_width=match_parent androi
资源详情
资源评论
资源推荐
Android Touch事件分发过程详解事件分发过程详解
本文以实例形式讲述了Android Touch事件分发过程,对于深入理解与掌握Android程序设计有很大的帮助作用。具体分析如
下:
首先,从一个简单示例入手:
先看一个示例如下图所示:
布局文件 :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
tools:context="com.example.touch_event.MainActivity"
tools:ignore="MergeRootFrame" >
<Button
android:id="@+id/my_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</FrameLayout>
MainActivity文件:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mBtn = (Button) findViewById(R.id.my_button);
mBtn.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("", "### onTouch : " + event.getAction());
return false;
}
});
mBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("", "### onClick : " + v);
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("", "### activity dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
}
当用户点击按钮时会输出如下Log:
08-31 03:03:56.116: D/(1560): ### activity dispatchTouchEvent
08-31 03:03:56.116: D/(1560): ### onTouch : 0
08-31 03:03:56.196: D/(1560): ### activity dispatchTouchEvent
08-31 03:03:56.196: D/(1560): ### onTouch : 1
08-31 03:03:56.196: D/(1560): ### onClick : android.widget.Button{52860d98 VFED..C. ...PH... 0,0-1080,144 #7f05003d app:id/my_button}
我们可以看到首先执行了Activity中的dispatchTouchEvent方法,然后执行了onTouch方法,然后再是dispatchTouchEvent –>
onTouch, 最后才是执行按钮的点击事件。这里我们可能有个疑问,为什么dispatchTouchEvent和onTouch都执行了两次,
而onClick才执行了一次 ? 为什么两次的Touch事件的action不一样,action 0 和 action 1到底代表了什么 ?
覆写过onTouchEvent的朋友知道,一般来说我们在该方法体内都会处理集中touch类型的事件,有ACTION_DOWN、
ACTION_MOVE、ACTION_UP等,不过上面我们的例子中并没有移动,只是单纯的按下、抬起。因此,我们的触摸事件也只
有按下、抬起,因此有2次touch事件,而action分别为0和1。我们看看MotionEvent中的一些变量定义吧:
public final class MotionEvent extends InputEvent implements Parcelable {
// 代码省略
public static final int ACTION_DOWN = 0; // 按下事件
public static final int ACTION_UP = 1; // 抬起事件
public static final int ACTION_MOVE = 2; // 手势移动事件
public static final int ACTION_CANCEL = 3; // 取消
// 代码省略
}
可以看到,代表按下的事件为0,抬起事件为1,也证实了我们上面所说的。
在看另外两个场景:
1、我们点击按钮外的区域,输出Log如下 :
08-31 03:04:45.408: D/(1560): ### activity dispatchTouchEvent08-31
03:04:45.512: D/(1560): ### activity dispatchTouchEvent
2、我们在onTouch函数中返回true, 输出Log如下 :
08-31 03:06:04.764: D/(1612): ### activity dispatchTouchEvent
08-31 03:06:04.764: D/(1612): ### onTouch : 0
08-31 03:06:04.868: D/(1612): ### activity dispatchTouchEvent
08-31 03:06:04.868: D/(1612): ### onTouch : 1
以上两个场景为什么会这样呢 ? 我们继续往下看吧。
Android Touch事件分发事件分发
那么整个事件分发的流程是怎样的呢 ?
简单来说就是用户触摸手机屏幕会产生一个触摸消息,最终这个触摸消息会被传送到ViewRoot ( 看4.2的源码时这个类改成了
ViewRootImpl )的InputHandler,ViewRoot是GUI管理系统与GUI呈现系统之间的桥梁,根据ViewRoot的定义,发现它并不是
一个View类型,而是一个Handler。InputHandler是一个接口类型,用于处理KeyEvent和TouchEvent类型的事件,我们看看源
码 :
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
// 代码省略
private final InputHandler mInputHandler = new InputHandler() {
public void handleKey(KeyEvent event, Runnable finishedCallback) {
startInputEvent(finishedCallback);
dispatchKey(event, true);
}
public void handleMotion(MotionEvent event, Runnable finishedCallback) {
startInputEvent(finishedCallback);
dispatchMotion(event, true); // 1、handle 触摸消息
}
};
// 代码省略
// 2、分发触摸消息
private void dispatchMotion(MotionEvent event, boolean sendDone) {
int source = event.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
dispatchPointer(event, sendDone); // 分发触摸消息
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
dispatchTrackball(event, sendDone);
} else {
// TODO
Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
if (sendDone) {
finishInputEvent();
}
}
}
// 3、通过Handler投递消息
private void dispatchPointer(MotionEvent event, boolean sendDone) {
Message msg = obtainMessage(DISPATCH_POINTER);
msg.obj = event;
msg.arg1 = sendDone ? 1 : 0;
sendMessageAtTime(msg, event.getEventTime());
}
@Override
public void handleMessage(Message msg) { // ViewRoot覆写handlerMessage来处理各种消息
switch (msg.what) {
// 代码省略
case DO_TRAVERSAL:
if (mProfile) {
Debug.startMethodTracing("ViewRoot");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
break;
case DISPATCH_POINTER: { // 4、处理DISPATCH_POINTER类型的消息,即触摸屏幕的消息
MotionEvent event = (MotionEvent) msg.obj;
try {
deliverPointerEvent(event); // 5、处理触摸消息
} finally {
event.recycle();
if (msg.arg1 != 0) {
finishInputEvent();
}
if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
}
} break;
// 代码省略
}
// 6、真正的处理事件
private void deliverPointerEvent(MotionEvent event) {
if (mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
}
boolean handled;
if (mView != null && mAdded) {
// enter touch mode on the down
boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
if (isDown) {
ensureTouchMode(true); // 如果是ACTION_DOWN事件则进入触摸模式,否则为按键模式。
}
if(Config.LOGV) {
剩余10页未读,继续阅读
weixin_38728183
- 粉丝: 5
- 资源: 942
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0