zoukankan      html  css  js  c++  java
  • 基于监听的事件处理——事件和事件监听器

         当外部动作在Android组件上执行操作时,系统会自动生成事件对象,这个事件对象会作为参数传给事件源上注册的事件监听器。

         事件监听的处理模型涉及三个成员:事件源、事件和事件监听器,其中事件源最容易创建,任意界面组件都看作为事件源;事件的产生无须程序员关心,它是由系统自动产生的;所以实现事件监听器是整个事件处理的核心。

         Android对事件监听模型做了进一步进化:如果事件源触发的事件足够简单、事件里封装的事件比较有限,那就无须封装事件对象、将事件对象传入事件监听器。

         但对于键盘事件、触摸屏事件等,此时程序需要获取事件发生的详细信息:例如键盘事件需要获取是哪个键触发的事件;触摸屏事件需要获取事件发生的位置等,对于这种包含更多信息的事件,Android同样会将事件信息封装成XxxEvent对象,并把该对象作为参数传入事件处理器。

         实例:控制飞机移动

         下面以一个简单的飞机游戏为例来介绍键盘事件的监听。游戏中的飞机会随用户单击键盘的动作而移动;单击不同的键盘,飞机向不同的方向移动。

         为了实现该程序,先开发一个自定义View,该View负责绘制游戏的飞机,该View类的代码如下。

    package com.example.studyevent;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.view.View;
    
    public class PlaneView extends View {
        public float currentX;
        public float currentY;
        Bitmap plane;
        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);
        }
    }

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

         该游戏几乎不需要界面布局,该游戏直接使用PlaneView做为Activity显示的内容,并为该PlaneView增加键盘事件监听器即可。下面是该Activty代码。

        

    package com.example.studyevent;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.DisplayMetrics;
    import android.view.Display;
    import android.view.KeyEvent;
    import android.view.Menu;
    import android.view.View;
    import android.view.View.OnKeyListener;
    import android.view.Window;
    import android.view.WindowManager;
    
    public class PlaneGameActivity extends Activity {
         //定义飞机的移动速度
        private int speed=10;
        @Override
        protected 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();
            DisplayMetrics metrics=new DisplayMetrics();
            //获取屏幕宽和高
            display.getMetrics(metrics);
            //设置飞机的初始位置
            planeView.currentX=metrics.widthPixels/2;
            planeView.currentY=metrics.heightPixels-40;
            //为draw组件键盘事件绑定监听器
            planeView.setOnKeyListener(new OnKeyListener(){
    
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    // TODO Auto-generated method stub
                    //获取由哪个触发的事件
                    switch(event.getKeyCode())
                    {
                     //控制飞机下降
                    case KeyEvent.KEYCODE_S:
                        planeView.currentY+=speed;
                        break;
                        //控制飞机上移
                    case KeyEvent.KEYCODE_W:
                        planeView.currentY-=speed;
                        break;
                    case KeyEvent.KEYCODE_A:
                        planeView.currentX-=speed;
                        break;
                    case KeyEvent.KEYCODE_D:
                        planeView.currentX+=speed;
                    break;
                    
                    }
                    //通知planeView组件重绘
                    planeView.invalidate();
                    return true;
                }});
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.plane_game, menu);
            return true;
        }
    
    }

       上面程序中的粗体字代码就是控制飞机移动的关键代码——由于程序需要根据用户按下的键来确定飞机的移动方向,所以上面的程序先调用KeyEvent(事件对象)的getKeyCode()来获取触发事件的键,然后根据不同的键来改变游戏中飞机的坐标。

        正如前面提到的:如果事件发生时有比较多的信息需要传给事件监听器,那么就需要将事件信息封装成Event对象,该Event对象将作为参数传入事件处理函数。

        运行上面的程序将看到下图所示效果。

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

         在基于监听的事件处理模型中,事件监听器必须实现事件监听器接口,Android为不同的界面组件提供了不同的监听器接口,这些接口通常以内部类的形式存在。以View类为例,它包含了如下几个内部接口。

    • View.OnClickListener:单击事件的事件监听器必须实现的接口。
    • View.OnCreateContextMenuListener:创建上下文文菜单事件的事件监听器必须实现的接口。
    • View.OnFocusChangeListener:焦点改变事件的事件监听器必须实现的接口。
    • View.OnKeyListener:按键事件的事件监听器必须实现的接口。
    • View.OnLongClickListener:长单击事件的事件监听器必须实现的接口。
    • View.OnTouchListener:触摸屏事件的事件监听器必须实现的接口。

       通过上面的介绍不难看出,所谓事件监听器,其实就是实现了特定接口的Java类的实例。在程序中实现事件监听器,通常有如下几种形式。

    •  内部类形式:将事件监听器类定义成当前类的内部类。
    •  外部类形式:将事件监听器类定义成一个外部类。
    •  Actviy本身作为事件监听器类:让Activity本身实现监听器接口,并实现事件处理方法。
    •  匿名内部类形式:使用匿名内部类创建事件监听器对象。 

                  

        

       

  • 相关阅读:
    6.1 tar:打包备份
    6.3-4 zip、unzip
    6.5 scp:远程文件复制
    S7 Linux用户管理及用户信息查询命令
    7.6 passwd:修改用户密码
    7.2-5 usermod
    DES
    FreeRTOS笔记
    第4章 裸机系统和多任务系统
    第008课_第1个ARM落版程序及引申
  • 原文地址:https://www.cnblogs.com/wolipengbo/p/3406621.html
Copyright © 2011-2022 走看看