android学习笔记(47)事件和事件监听器

文章标签: android,android事件
2015-1-20 18:04:25     人阅读    

            当外部动作在Android组件上进行操作时,系统会自动生成事件 对象,这个事件对象会作为参数传给注册到事件源上的事件监听器。
            事件监听的处理模型涉及三个成员:事件源、事件和事件监听器,其中事件源最容易创 建,任意界面组件都可作为事件源;事件的产生无须程序员关心,它是由系统自动产生的, 所以,实现事件监听器是整个事件处理的核心。
             但在上面的程序中,我们并未发现事件的踪迹,这是什么原因呢?这是因为Android对 事件监听模型做了进一步简化:如果事件源触发的事件足够简单、事件里封装的信息比较有限,那就无须封装事件对象、将事件对象传入事件监听器。
             但对于键盘事件、触摸屏事件等,此时程序需要获取事件发生的详细信息:例如键盘事 件需要获取是哪个键触发的事件;触摸屏事件需要获取事件发生的位置等,对于这种包含更 多信息的事件,Android同样会将事件信息封装成XxxEvent对象,并把该对象作为参数传入 事件处理器。
实例:控制飞机移动
下面以一个简单的飞机游戏为例来介绍键盘事件的监听:游戏中的飞机会随用户单击键 的动作而移动:单击不同的键,飞机向不同方向移动。
为了实现该程序,我们先开发一个自定义View,该View负责绘制游戏的飞机,该View

public PlaneView(Context context)
{
super(context);
// TODO Auto-generated constructor stub
//定义飞机图片
plane = BitmapFactory.decodeResource(context.getResources() ,R.drawable.plane); setFocusable(true);
}
@Override
public void onDraw (Canvas canvas)
{
super.onDraw(canvas);
//创建画笔
Paint p = new Paint();
//绘制飞机
canvas.drawBitmap(plane , currentX , currentY , p);

             上面的PlainView足够简单,因为这个程序只需要绘制玩家自己控制的飞机,没有增加 “敌机”,所以比较简单。如果游戏中还需要增加“敌机”,那么还需要增加数据来控制敌机 的坐标,并会View上控制敌机。


该游戏几乎不需要页面布局,该游戏直接使用PlaneView作为Activity显示的内容,并 为该PlaneView增加键盘事件监听器即可。下面是该程序的Activity代码。
程序清单:codes\03\3.2\plane\src\org\crazyit\event\PlaneGamejava

package org.crazyit.event;

import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.Window;
import android.view.WindowManager;

public class PlaneGame extends Activity
{
 // 定义飞机的移动速度
 private int speed = 12;

 @Override
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  // 去掉窗口标题
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  // 全屏显示
  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
   WindowManager.LayoutParams.FLAG_FULLSCREEN);
  // 创建PlaneView组件
  final PlaneView planeView = new PlaneView(this);
  setContentView(planeView);
  planeView.setBackgroundResource(R.drawable.back);
  // 获取窗口管理器
  WindowManager windowManager = getWindowManager();
  Display display = windowManager.getDefaultDisplay();
  // 获得屏幕宽和高
  int screenWidth = display.getWidth();
  int screenHeight = display.getHeight();
  // 设置飞机的初始位置
  planeView.currentX = screenWidth / 2;
  planeView.currentY = screenHeight - 40;
  // 为draw组件键盘事件绑定监听器
  planeView.setOnKeyListener(new OnKeyListener()
  {
   @Override
   public boolean onKey(View source, int keyCode, KeyEvent event)
   {
    // 获取由哪个键触发的事件
    switch (event.getKeyCode())
    {
     // 控制飞机下移
     case KeyEvent.KEYCODE_DPAD_DOWN:
      planeView.currentY += speed;
      break;
     // 控制飞机上移
     case KeyEvent.KEYCODE_DPAD_UP:
      planeView.currentY -= speed;
      break;
     // 控制飞机左移
     case KeyEvent.KEYCODE_DPAD_LEFT:
      planeView.currentX -= speed;
      break;
     // 控制飞机右移
     case KeyEvent.KEYCODE_DPAD_RIGHT:
      planeView.currentX += speed;
      break;
    }
    // 通知planeView组件重绘
    planeView.invalidate();
    return true;
   }
  });
 }
}

              上面的程序中粗体字代码就是控制飞机移动的关键代码——由于程序需要根据用户按下 的键来确定飞机的移动方向,所以上面的程序先调用了 KeyEvent(事件对象)的getKeycode() 来获取触发事件的键,然后针对不同的键来改变游戏中飞机的坐标。
                  正如前面提到的:如果事件发生时有比较多的信息需要传给事件监听器,那么就需要将 事件信息封装成Event对象,该Event对象将作为参数传入事件处理函数。

                 对于“游戏”,当用户按下模拟器右边的4个方向键时,将可以看到“游戏”中的飞机可以上、下、左、右自由移动。

在基于事件监听的处理模型中,事件监听器必须实现事件监 听器接口,Android为不冋的界面组件提供了不同的监听器接口,
这些接口通常以内部类的形式存在。以View类为例,它包含了 如下几个内部接口。
View.OnClickListener:单击事件的事件监听器必须实现的接口。
View.OnCreateContextMenuListener:创建上下文菜单事件的事件监听器必须实现的接口。
View.onFocusChangeListener:焦点改变事件的事件监听器必须实现的接口。 
View.OnKeyListener按键事件的事件监听器必须实现的接口。

提示: 
             上面这个“游戏”还只是一个“雏型”,为了增加这个游戏的可玩性,可以考虑为游戏随机地增加“敌机”,并让“敌机”在屏幕上移动。如果想增加对战效果, 还可以考虑增加一个键盘监听器:监听特定按键,特定按键激发飞机射出子弹。
View.OnLongClickListener:长单击事件的事件监听器必须实现的接口。
View.OnTouchListener:触摸屏事件的事件监听器必须实现的接口。

提示:
             实际上可以把事件处理模型简化成如下理解:当事件源组件上发生事件时,系统将会执行该事件源组件上监听器的对应处理方法。与普通Java方法调用不同 的是:普通Java程序里的方法由程序主动调用的,事件处理中的事件处理器方法 是由系统负责调用。
通过上面的介绍不难看出,所谓事件监听器,其实就是实现了特定接口的Java类的实例。 在程序中实现事件监听器,通常有如下几种形式。
内部类形式:将事件监听器类定义成当前类的内部类。
外部类形式:将事件监听器类定义成一个外部类。
Activity本身作为事件监听器类:让Activity本身实现监听器接口,并实现事件处理方法。
匿名内部类形式:使用匿名内部类创建事件监听器对象。


原文地址:http://www.itmmd.com/201501/528.html
该文章由 萌萌的IT人 整理发布,转载须标明出处。

Android Lollipop 5.0 无法获得后台运行的activity名称   上一篇
下一篇  android ViewPager改变 Fragment 中的TextView的值
精彩回复
我要追加问题,请求站长解决!
姓名:       

《程序员app》专门为程序员量身定做!