第5回 二弟呀,面子工程很重要

1.1. 控件的事件处理机制

1.1.1.事件种类

在Android中事件包括两类,一类是按键事件,一类是触摸事件。这两大类事件构成了Android事件的框架。按键事件是指手机键盘被按下的事件,包括按下,释放和长按。触摸事件相对复杂一些,最基本的触摸事件有三种,包括ACTION_DOWN,ACTION_MOVE和ACTION_UP,分别对应手指按下,拖动和抬起的操作。一次简单的触摸操作包含的一次ACTION_DOWN,多次ACTION_MOVE以及一次ACTION_UP,而且顺序是固定的,一定是按照ACTION_DOWN,ACTION_MOVE,ACTION_UP的顺序发生。如果将这三种基本的触摸事件进行组合会产生很多复杂的事件,比如点击事件由一个ACTION_DOWN和一个ACTION_UP,长按事件由一个ACTION_DOWN和一段时间组成,滚动和滑动等事件由一个ACTION_DOWN和多个ACTION_MOVE组成。

1.1.2.事件传递机制

Android中事件由WindowManagerService获取,并通过共享内存和管道的方式传递给ViewRoot的。它是整个View树和WindowManager之间的事件信息的翻译者。当事件到达根结点之后,根结点再向它自己或者子结点分发事件,直到有控件处理或者丢弃。

我们知道在View树中有两类结点一类是ViewGroup,一类是View。以ACTION_DOWN事件为例,在ViewGroup中关于事件传递和处理的有三个方法,分别是:

public boolean dispatchTouchEvent(MotionEventev) 用于事件的分发

public boolean onInterceptTouchEvent(MotionEventev) 用于事件的拦截

public booleanonTouchEvent(MotionEvent ev)  处理事件

而View中只包含dispatchTouchEvent()和onTouchEvent()方法。也就是说View不会执行事件的拦截,只会处理事件。

dispatchTouchEvent负责分发事件,ACTION_DOWN事件最先到达的就是最顶层view的dispatchTouchEvent,然后它进行分发,如果返回true,则继续等待下次事件,返回false,则交给这个view的interceptTouchEvent方法来决定是否要拦截这个事件。如果interceptTouchEvent返回true,也就是拦截掉了,则交给它的onTouchEvent来处理,处理之后,如果返回false表示这个事件还没有被处理完成,还需要其他的处理,之前讲到的ListView中的两个长按的响应例子就是利用这个特性做到的,返回true表示已经处理完了。随后的ACTION_MOVE和ACTION_UP事件都会在这个View上处理,而不会再次进行选择。如果interceptTouchEvent返回false,那么就传递给子view,由子view的dispatchTouchEvent再来开始这个事件的分发,从而一层一层传递下去。

如果事件传递到某一层的子view的onTouchEvent上了,这个方法返回了false,那么这个事件会从这个view往上传递,都是onTouchEvent来接收。而如果传递到最上面的onTouchEvent也返回false的话,这个事件就会“消失”,而且接收不到后序的ACTION_MOVE和ACTION_UP事件。

1.1.3.事件处理机制

Android中的事件处理分为两种:监听和回调。两种方式在处理事件上有很大的不同,具体表现在如下几个方面:

两种方式处理的事件种类不同,具体来说,监听处理的是点击,长按,创建上下文菜单,焦点变化等事件,而回调处理的是触摸屏操作(比如ACTION_DOWN,ACTION_MOVE和ACTION_UP事件)以及按键操作。两种事件处理方式的程序结构不同,监听方式处理需要建立监听器对象,并为View设置相应的监听器对象,而回调方式处理的事件比监听方式要细致的多,当用户在GUI组件上触发某事件时,由该组件自身特定的函数负责处理该事件,通常通过重写Override组件类的事件处理函数实现事件的处理。因此,在实际的操作中,监听方式比回调方式应用的场景要多很多。

关于监听方式的例子在前面小节中已经有很多了,在这里我们讲一个回调方式处理事件的例子。回调方式需要重写控件,在此我们重写一个Button,定义如下:

TestButton.java代码清单5-33:

/**

 * TestButton自定义按钮,重写了onKeyDown方法

* @author孔明

 */

publicclass TestButton extends Button {

public TestButton(Context context) {

super(context);

}

public TestButton(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

public TestButton(Context context, AttributeSet attrs) {

super(context, attrs);

}

// 重写了onKeyDown方法,在按键时本方法自动被回调

@Override

public boolean onKeyDown(intkeyCode, KeyEvent event) {

switch (keyCode) {

case KeyEvent.KEYCODE_DPAD_CENTER:

// 按下按键是显示一个提示

DisplayToast("你按下中间键");

break;

case KeyEvent.KEYCODE_DPAD_DOWN:

                                   DisplayToast("你按下下方向键");

                                          break;

                                 case KeyEvent.KEYCODE_DPAD_LEFT:

                                   DisplayToast("你按下左方向键");

                                          break;

                                case KeyEvent.KEYCODE_DPAD_RIGHT:

                                   DisplayToast("你按下右方向键");

                                          break;

                                case KeyEvent.KEYCODE_DPAD_UP:

                                   DisplayToast("你按下上方向键");

                                          break;

}

                                return super.onKeyDown(keyCode, event);

}

// 显示提示的方法

public void DisplayToast(String str) {

Toast.makeText(this.getContext(), str, Toast.LENGTH_LONG).show();

}

}

同时,我们新建一个Activity,命名为EventHandleActivity,内容如下:

publicclass EventHandleActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.event_handle);

}

}

在这个Activity中使用的布局文件为event_handle.xml,内容如下:

event_handle.xml代码清单5-34:

<?xml version=“1.0” encoding=“utf-8”?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical">

<!--  使用自定义的TestButton -->

<com.firstpeople.chapter0520.TestButton

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="自定义按钮"/>

</LinearLayout>

布局文件中使用一个自定义的控件时,需要指出该控件所在的具体的包路径。

运行程序,我们截图如5-50所示:

图5-50 自定义button点击事件示意图

从图上可以看到我们在程序里面添加的提示信息,需要注意的是需要将按钮置为选中状态的情况下才会有相应的提示,也就是说需要将按钮置为焦点时onKeyDown()方法才会被执行。

回调方式处理事件的方法还有其他几个:

boolean onKeyMultiple(intkeyCode,intrepeatCount,KeyEventevent)用于在多个事件连续时发生,用于按键重复,必须重写@Override实现;

boolean onKeyDown(intkeyCode,KeyEventevent)用于在按键进行按下时的操作;

boolean onKeyUp(intkeyCode,KeyEventevent)用于在按键进行释放时的操作;

boolean onKeyLongPress(intkeyCode,KeyEventevent)当你长时间按键时的操作。

孔明:一般情况下,我们使用监听方式来处理事件就足够了,但是作为编程大牛的我们来说,一定要会使用回调方式,至少要知道其中的原理哦~~

 

 

 


1.2. 玄德有话说

张飞:大哥!我头晕!我先走一步!

刘备:三弟!三弟!撑住!卧龙先生讲完了!真的讲完了!

张飞:终于讲完了吗?天呐,我以为这一回永远也不会结束了!

孔明:Android界面的内容确实很多,不过也非常重要,这是Android开发的基础!

关羽:我有一个问题哈,这么多控件、布局,我们如何记得住呢?

孔明:很简单,不用记,放轻松!最重要的是理解原理,知道哪里能查到,善于检索资料。时间长了,你不用记这些控件也能深深的扎根在你的脑子里,与你合为一体!

刘备:孔明说的太玄了吧,我也有一个问题,刚才学习布局时,那么多布局好像都能达到效果,那么我该如何选择呢?

孔明:世上有很多路都能达到终点,有的比较快,有的比较安全,最好是又快又安全。懂了吗?

张飞:请用中文,谢谢!

孔明:选择布局方式的时候要选用兼容性强的,简便的方式进行。要尽可能使多种屏幕分辨率的终端都能很好显示,这其实是一个非常困难的事情。只有多做项目,多写代码,多看多想,自然能达到写界面就跟随手涂鸦般轻松的地步

刘备:孔明,我还有一个问题特别想问你。

孔明:说。

刘备:你为什么一直在茅房里?

孔明:很简单……因为我还没上完厕所。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值