android 键盘事件和屏幕事件的运行原理及交互实现
字体:[ ] 类型:转载 时间:
当在自定义View或者做游戏的时候,我们常常会用到键盘触发事件和屏幕触发事件!在自定义的View里的键盘触发事件和屏幕触发事件和activity里的键盘触发事件和屏幕触发事件是怎么样交互的呢,接下来为您详细介绍,感兴趣的朋友可以了解下哦
当在自定义View或者做游戏的时候,我们常常会用到键盘触发事件和屏幕触发事件!在自定义的View里的键盘触发事件(比如:onKeyDown(int keyCode, KeyEvent event))和屏幕触发事件(onTouchEvent(MotionEvent event))和activity里的键盘触发事件(比如:onKeyDown(int keyCode, KeyEvent event))和屏幕触发事件(onTouchEvent(MotionEvent event))是怎么样交互的呢?是怎样的一个运行原理呢?下面来看看: 1、屏幕触发事件:哪个activity或者视图,控件在最上层就最先触发这个控件里的屏幕触发事件,返回值如果是默认或者false就会一层一层的往下传递!如果返回值是true,则在执行完动作之后不会往下传递! 2、键盘触发事件:这个原理和屏幕触发事件差不多,但是不同的时,在没有设置控件处于焦点时,一般按键盘里的按键触发的是activity里的键盘触发事件(比如:onKeyDown(int keyCode, KeyEvent event))。 下面来举个例子: 比如在做游戏的时候,我们经常自定义视图,我们一般都喜欢和使用触发本视图(GameView)里的键盘触发事件和屏幕触发事件,但是比如:onKeyDown(int keyCode, KeyEvent event)),一般我们按键盘的时候直接触发的是activity里的键盘触发事件,怎样让它直接触发(GameView)里的键盘触发事件呢? 第一种方法: 例子1:
代码如下: View Code package net.loonggg. import android.app.A import android.os.B import android.view.KeyE import android.view.MotionE public class MainActivity extends Activity { private GameView gameV @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gameView = new GameView(this); setContentView(gameView); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("MainActivity:" + " keyCode:" + keyCode + " evnet:" + event); return super.onKeyDown(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("MainActivity:" + " event:" + event + " x:" + event.getX() + " y:" + event.getY()); return super.onTouchEvent(event); } } package net.loonggg. import android.content.C import android.graphics.C import android.graphics.C import android.graphics.P import android.view.KeyE import android.view.MotionE import android.view.V public class GameView extends View { private P private int pointX; private int pointY; public GameView(Context context) { super(context); // 设置GameView获得焦点 this.setFocusable(true); paint = new Paint(); paint.setColor(Color.YELLOW); Thread t = new Thread(new MyThread()); t.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(pointX, pointY, 15, paint); } class MyThread implements Runnable { @Override public void run() { while (true) { try { Thread.sleep(3000); pointY = pointY + 10; pointX = pointX + 10; if (pointX & 200) {
} } catch (InterruptedException e) { e.printStackTrace(); } GameView.this.postInvalidate(); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("GameView:" + " keyCode:" + keyCode + " evnet:" + event); //此事件不会传播出去
} @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("GameView:" + " event:" + event + " x:" + event.getX() + " y:" + event.getY()); //此事件不会传播出去
第二种方法:
代码如下: View Code package net.loonggg. import android.app.A import android.os.B import android.view.KeyE import android.view.MotionE public class MainActivity extends Activity { private GameView gameV @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gameView = new GameView(this); setContentView(gameView); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("MainActivity:" + " keyCode:" + keyCode + " evnet:" + event); //把事件传递给gameView gameView.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("MainActivity:" + " event:" + event + " x:" + event.getX() + " y:" + event.getY()); //把事件传递给gameView gameView.onTouchEvent(event); return super.onTouchEvent(event); } } package net.loonggg. import android.content.C import android.graphics.C import android.graphics.C import android.graphics.P import android.view.KeyE import android.view.MotionE import android.view.V public class GameView extends View { private P private int pointX; private int pointY; public GameView(Context context) { super(context); paint = new Paint(); paint.setColor(Color.YELLOW); Thread t = new Thread(new MyThread()); t.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(pointX, pointY, 15, paint); } class MyThread implements Runnable { @Override public void run() { while (true) { try { Thread.sleep(3000); pointY = pointY + 10; pointX = pointX + 10; if (pointX & 200) {
} } catch (InterruptedException e) { e.printStackTrace(); } GameView.this.postInvalidate(); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("GameView:" + " keyCode:" + keyCode + " evnet:" + event); return super.onKeyDown(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { System.out.println("GameView:" + " event:" + event + " x:" + event.getX() + " y:" + event.getY()); return super.onTouchEvent(event); } }
在这里,推荐使用第二种方法,因为第一种方法有的模拟器不能够使用! 囧神的世界你不懂,虫哥的生活你没有,只有程序猿的世界大家才知道。程序猿们,为了自己的精彩世界奋斗吧,努力吧!加油……
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&本帖子已过去太久远了,不再提供回复功能。Android 【真机】与【模拟器】触摸屏事件的模拟差异分析_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Android 【真机】与【模拟器】触摸屏事件的模拟差异分析
来源:Linux社区&
作者:yiyaaixuexi
真机和模拟器的差异问题,是永恒的话题,问不完的为什么,解不完的迷。模拟器的存在,有它的作用,但不要什么都相信模拟器。除非你是Android纯上层应用开发人员或者爱好者,否则我建议你扔掉模拟器。它理想化的引导给我们添了不少麻烦。当然,这也是件好事。最起码,让我有兴趣去寻求***,让我收获了更多。
&&&&& 问题的缘由是有个自动化测试的需求,我需要写脚本模拟点击触摸屏的一系列操作,以代替手工测试(话说~遇上连续启动1000次camera并且拍照后退出这种变态测试,你们都是怎么做的?)。以此来证明:头儿,此bug真的解了!&&&
&&&& Linux上可以通过sendEvent来模拟键盘或者鼠标点击事件,而Android是基于Linux2.6的,所以也可以模拟点击事件。网络文章很多都给出这样一段数据信息,告诉你怎么去实现模拟点击:
adb shell sendevent /dev/input/event0 3 0 110&&&&&& //x坐标adb shell sendevent /dev/input/event0 3 1 70&&&&&&&& //y坐标adb shell sendevent /dev/input/event0 1 330 1&&&&&& //按下状态,准确的说是有压力值adb shell sendevent /dev/input/event0 0 0 0&&&&&&&&&& //必要的一行数据adb shell sendevent /dev/input/event0 1 330 0&&&&&& //抬起状态,无压力值adb shell sendevent /dev/input/event0 0 0 0&&&&&&&&&& //必要的一行,相当于终止一段完整数据的标致
用上面的方法可以点击模拟器的(110,70)点,但是,在真机上,却不可以,原因有两点。
&&&&&? 1.& /dev/input/event0 ×
&&&&&&模拟器上只有一个/dev/input/event0,但是真机上不是(如果还真是,那你这设备还是别出厂了-_-||)。
用cat获得的设备对应event信息:
# cat /proc/bus/input/devicesI: Bus=0000 Vendor=0000 Product=0000 Version=0000N: Name="qtouch-touchscreen"P: Phys=S: Sysfs=/devices/virtual/input/input5U: Uniq=H: Handlers=event5B: EV=bB: KEY=400 0 4 0 0 0 0 0 0 0 0B: ABS=30003"qtouch-touchscreen"不是规定死的event几,话说1234567都有可能,看你设备了。&
&?&2.& 数据类型 ×
&&&&& 探究原因的时候,通过:
#adb shell getevent /dev/input/event5 & getvalue
可以得到:
&0007c8&000771&000001&000000&000010&000000
这和我之前所想象的坐标信息不一样,看到c,就知道是16进制数喽,第一反应就是做个10进制的转换。具体怎么转换?
int main (int argc, char *argv[]) 点点点... (这个.c 还不会写?不会写还不会搜吗?)
可以得到:
3 53 1992&3 54 1905 3 56 1 0 2 0&3 55 16
先不管为什么,做个测试验证下结果:
adb shell sendevent /dev/input/event5 3 53 1992 adb shell sendevent /dev/input/event5 3 54 1905 adb shell sendevent /dev/input/event5 3 56 1 adb shell sendevent /dev/input/event5 0 2 0 adb shell sendevent /dev/input/event5 3 55 16 adb shell sendevent /dev/input/event5 0 0 0
这里提一下,倘若操作的数据特别大,那我们可以利用vi的强大,在脚本中实现批量数据的转换,例如:
vim '+%normal gg' '+.,$g/^/s//adb shell sendevent \/dev\/input\/event5 /g' '+wq' value
结果可以实现点击
既然测试的结果证明那乱七八糟的数是对的,那就必究其缘由!其实问题的根本原因,是因为手里的真机设备已经支持了多点触摸。
在Android中,多点触摸功能依赖于 中定义的以下几个主要的软件位:
public&class&RawInputEvent&{& &&
&&public&static&final&int&ABS_MT_TOUCH_MAJOR&=&
&&public&static&final&int&ABS_MT_TOUCH_MINOR&=&
&&public&static&final&int&ABS_MT_WIDTH_MAJOR&=&
&&public&static&final&int&ABS_MT_WIDTH_MINOR&=&
&&public&static&final&int&ABS_MT_ORIENTATION&=&
&&public&static&final&int&ABS_MT_POSITION_X&=&
&&public&static&final&int&ABS_MT_POSITION_Y&=&
&&public&static&final&int&ABS_MT_TOOL_TYPE&=&
&&public&static&final&int&ABS_MT_BLOB_ID&=&
中,系统创建了一个线程,把所有的
事件放入一个队列,在
的最后,将多点事件类型转化为单点事件类型,返回一个??的
相关资讯 & & &
& (07/13/:14)
& (08/11/:27)
& (05/06/:13)
& (04/17/:32)
& (05/31/:15)
& (04/02/:07)
同意评论声明
发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款android游戏开发(二)触屏事件处理
在上一章我们没有把标题栏和状态栏给去掉& ,& 如果在游戏中 是不会显示 显示标题栏和状态栏的, 如何去掉了, 很简单,& 在mainActivity 的onCreate方法中加入下面两句 即可& :
&requestWindowFeature(Window.FEATURE_NO_TITLE); //设置无标题
&getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置全屏
&赶紧去试试吧 , 写程序就是要 多试 嘻嘻..
图片有了 ,我们怎么样才能让图片有行为呢 ?& 那就需要人机交互了,通过触摸屏让游戏具有行为
先在这里 说明下android 的坐标系
android 的坐标系& 左上定点为原点坐标(0,0), 向右为X轴,向下为Y轴 说明这个位置是因为有些游戏引擎是 以 左下为原点的哦 , 大家要记住喔,后面如果用引擎的话 也有个概念
下面 我们来看看android 的 触摸屏事件是怎么处理的
我们先来分析下 现在的用户界面 都是通过事件驱动 实现人机交互的,当屏幕的界面接受到事件时 根据不同情况 进行不同的处理 就可以实现人机交互了
android 支持的触摸屏事件有:按下、弹起、移动、双击、长按、滑动。
按下、弹起、移动(down、move、up)是简单的触摸屏事件 我们本章就来说说这个东东.
而双击、长按、滑动、滚动需要根据运动的轨迹来做识别的。在中有专门的类去识别,android.view.GestureDetector。 这一块我们后面的章节 在讲
那如何实现呢?
&在Android中任何一个控件和Activity都是间接或者直接继承于android.view.View。一个View对象可以处理测距、布局、绘制、焦点变换、滚动条,以及触屏区域自己表现的按键和手势,因为我们的view 是继承了surfaceView,surfaceView又是继承view 所以要实现简单的触摸屏事件,只需要重写父类view 里面的onTouchEvent 方法就可以实现简单的触屏屏事件了
下面我们来实现一个功能& 用上一章的程序 来实现 把图片显示在点击触摸屏的地方和图片能根据手指移动而移动
直接看代码
import android.content.C
import android.content.DialogI
import android.graphics.B
import android.graphics.BitmapF
import android.graphics.C
import android.graphics.C
import android.view.MotionE
import android.view.SurfaceH
import android.view.SurfaceV
import android.view.SurfaceHolder.C
&* android surfaceview触摸屏事件学习
&* @author mahaile
public class GameSurfaceView extends SurfaceView implements Callback{
& //线程标示位 当为false时停止刷新界面
&SurfaceHolder surfaceH
&GameViewThread gameViewT
&float x=0,y=0;
&int direction=0;& //图片运行方向 控制图片向上 或向下运动
&int width,
&Bitmap bitmap_
&public GameSurfaceView(Context context) {
&&super(context);
&&surfaceHolder=this.getHolder();
&&surfaceHolder.addCallback(this); //添加回调
&&bitmap_role=BitmapFactory.decodeResource(getResources(), R.drawable.role);
&&//设置焦点 如果不设置焦点的话 在该界面下 点击触摸屏是无效的 默认为false
&&setFocusable(true);
&public void onDraw(Canvas canvas){
&&canvas.drawColor(Color.BLACK);
&&canvas.drawBitmap(bitmap_role, x-bitmap_role.getWidth()/2, y-bitmap_role.getHeight()/2, null);
&&& //重写父类中的 onTouchEvent就可以***到& 触摸事件了 记住要设置焦点喔
&@Override
&public boolean onTouchEvent(MotionEvent event) {
&&if(event.getAction()==MotionEvent.ACTION_DOWN){ //处理屏幕屏点下事件 手指点击屏幕时触发
&&&x=event.getX();
&&&y=event.getY();
&&}else if(event.getAction()==MotionEvent.ACTION_UP){//处理屏幕屏抬起事件& 手指离开屏幕时触发
&&}else if(event.getAction()==MotionEvent.ACTION_MOVE){//处理移动事件 手指在屏幕上移动时触发
&&&x=event.getX();
&&&y=event.getY();
&&& //此处需要返回true 才可以正常处理move事件 详情见后面的& 说明
&public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {&
&public void surfaceCreated(SurfaceHolder surfaceHolder) {
&&//获取屏幕的 宽高 只有在 surface创建的时候 才有效 ,才构造方法中获取 宽高是获取不到的
&&width=this.getWidth();
&&height=this.getHeight();
&&//初始化绘图线程
&&gameViewThread=new GameViewThread();
&&gameViewThread.flag=
&&gameViewThread.start();
&public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
&&gameViewThread.flag= //销毁线程
&class GameViewThread extends Thread{
&&public void run(){
&&&while(flag){
&&&&Canvas canvas=
&&&&&canvas=surfaceHolder.lockCanvas(); //锁定画布 并获取canvas
&&&&&onDraw(canvas);//调用onDraw 渲染到屏幕
&&&&&surfaceHolder.unlockCanvasAndPost(canvas); //此步不要忘记了喔 否则界面上显示不出来的
&&&&}catch(Exception e){
&&&&&e.printStackTrace();
&&&&&Thread.sleep(10);//线程休眠时间& 控制帧数
&&&&} catch (InterruptedException e) {
&&&&&// TODO Auto-generated catch block
&&&&&e.printStackTrace();
&&&}& //每10毫秒刷新一次
MainActivity 类& 这里就不贴代码了,因为和上一章一样 ,很简单的
onTouchEvent() 返回值 解释
&&& onTouchEvent(),预设使用Oeverride这个方法,通常情況下去呼叫super.onTouchEvent()并传回布林值。但是这里要注意一点,预设如果去呼叫super.onTouchEvent()則很有可能super里面并没做任何事,并且回传false回來,一旦回传false回來,很可能后面的event (例如:Action_Move、Action_Up) 都会收不到了,所以为了确保保后面event能順利收到,要注意是否要直接呼super.TouchEvent()。
下一张 我们看看如果使用android的手势识别
最后还要注意一点:在初始化的时候不要忘记setFocusableInTouchMode(true);触屏模式获取焦点,比较类似 setFocusable(true);
&&&&&&& &&setFocusable(true);//此方法是用来响应按键!如果是自己定义一个继承自View的类,重新实现onKeyDown方法后,只有当该View获得焦点时才会调用onKeyDown方法,Actvity中的onKeyDown方法是当所有控件均没有处理该按键事件时,才会调用.
原代码下载地址:
& 在android 中使用触摸屏 在模拟机中 我们的鼠标当点击一次模拟器屏幕然后释放,先触发 ACTION_DOWN 然后 ACTION_UP ;如果是在屏幕上移动那么才会触发 ACTION_MOVE 的动作;这个很正常, 但在真机中呢 ,是不是 也是这样的呢 ?& ***是否定的& 如果我们那真机测试的话 流程如下
先触发 ACTION_DOWN 如果手指不抬起的话 会一直触发ACTION_MOVE事件(就是不移动也会触发)& 然后 ACTION_UP
原因有两点:第一点是因为,Android 对于触屏事件很敏感!第二点:虽然我们的手指感觉是静止没有移动,其实事实不是如此!当我们的手指触摸到手机屏幕上之后,感觉静止没动,其实手指在不停的微颤抖震动。 所以才会一直触发action_move事件&&
这样的情况对我们的程序有什么影响呢
比如我们app线程绘图时间每次用了10ms,当手指触摸屏幕,这短暂的0.1秒内大概会产生10个左右的MotionEvent ,并且会尽可能快的把这些event发给***线程, 这样的话在这一段时间内cpu可能忙于处理onTouchEvent事件 从而造成app 的界面没有足够资源去处理,而照成界面刷新一卡一卡的。
那么我们其实根本用不着按键响应这么多次,而是需要在我们每次绘图后,或者绘图前接受一次用户触摸事件就OK了,这样能让帧率不至于下降的太厉害不是么?!如果我们能把触屏***事件 触发的事件 给慢下来 不就是可以解决这个问题了吗& ,嘻嘻 就是这么优化的
public boolean onTouchEvent(MotionEvent event) {
&if(event.getAction()==MotionEvent.ACTION_DOWN){
&}else if(event.getAction()==MotionEvent.ACTION_UP){
&}else if(event.getAction()==MotionEvent.ACTION_MOVE){
&&&&&&&& synchronized(this){
&&&&&&&&&& try{
&&&&&&&&&&&&&& this.wait(Time);&&&& //让事件线程休眠 减少触发次数
&&&&&&&&&&& }catch(InterruptedException e){
&&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&& }&&&&&&&&
&&&&&&&&& }
&上面的代码 加到你的onTouch 里面 但有一点要注意喔 ,上面的线程同步对象使用了this ,如果这个类 也被别的类作为同步对象的话 ,可能发生死锁喔,& 如果这个类已经被作为了同步对象的话 ,& 我们重新初始化的时候 新new 一个对象 作为onTouch的同步对象就可以了
摘自 android,unity3d
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'