免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: didimm
打印 上一主题 下一主题

《android编程宝典》-连载。 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2013-04-15 15:29 |只看该作者
7.3.2 监听处理onKeyUp事件
下面通过实例的方式来为读者朋友们介绍如何处理键盘释放(onKeyUp)事件。
(1)编辑chapter7_2工程的MainActivity.java文件,重写Activity基类的onKeyUp()方法,源代码如下:
    @Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{//覆盖Activity基类的onKeyUp键盘释放事件
            if(KeyEvent.KEYCODE_BACK == keyCode)
{//如果返回键被释放
                    Toast.makeText(this, "返回键被释放", Toast.LENGTH_LONG).show();
                    return true;//事件被当前业务逻辑处理,不再继续往下传递
            }
else if(KeyEvent.KEYCODE_MENU == keyCode)
{//如果菜单键被释放
                    Toast.makeText(this, "菜单键被释放", Toast.LENGTH_LONG).show();
                    return true;
            }
else if(KeyEvent.KEYCODE_SEARCH == keyCode)
{//如果搜索键被释放
                    Toast.makeText(this, "搜索键被释放", Toast.LENGTH_LONG).show();
                    return true;
            }
            return super.onKeyUp(keyCode, event);
    }   
上述代码当中对Activity基类的onKeyUp(int keyCode, KeyEvent event)方法进行了重写,用来对键盘释放的事件进行捕获和相应的处理,onKeyUp方法的两个参数所表示的意思与onKeyDown(int keyCode, KeyEvent event)方法的参数的意思是一致的,笔者在这里就不再赘述。笔者在onKeyUp()方法当中分别对返回按键,菜单按键以及搜索按键的键盘释放事件进行了相关提示。
(2)右击工程chapter7_2,在弹出的快捷菜单中选择Run As|Android Application命令,当“菜单”键被释放的时候,运行效果如图7-5所示,当“搜索”按键被释放的时候,运行效果如图7-6所示:

论坛徽章:
0
12 [报告]
发表于 2013-04-15 15:32 |只看该作者
7.4  自定义监听器
在实际项目开发中,经常需要自定义监听器来实现自定义业务流程的处理,而且一般都不是基于GUI界面作为事件源的。这里以常见的app自动更新为例进行说明,在自动更新过程中,会存在两个状态:下载中和下载完成,而应用程序需要在这两个状态做不同的事情,“下载中”需要在UI界面上实时显示软件包下载的进度,“下载完成”后,取消进度条的显示。这里笔者通过实例方式来模拟一下这个过程,重点在说明自定义监听器的事件处理流程。
(1)新建工程chapter7_3,编辑res/layout/activity_main.xml文件,源代码参考光盘。
(2)新建自定义事件监听器接口DownloadListener.java文件,源代码如下:
public interface DownloadListener
{
        public void onDownloading(int progress);//下载过程中的处理函数
        public void onDownloaded();//下载完成的处理函数
}       
(3)新建下载工具类DownloadUtils.java文件,源代码如下:
public final class DownloadUtils
{
        //单例模式
        private static DownloadUtils instance = new DownloadUtils();
        private boolean isDownloading = true;//是否正在下载
        private int progress = 0;//下载进度
        private DownloadUtils(){}       
        public static DownloadUtils getInstance()
{
                return instance;
        }
        public void download(DownloadListener listener)
{
                        while(isDownloading)//如果正在下载
{
                                listener.onDownloading(progress);  //下载进度发生变化,调用onDownloading()方法
                                SystemClock.sleep(1000);//线程休眠1S
                                progress += 10;
                                if(progress > 100)
{//如果进度条的值大于100
                                        isDownloading = false;//下载完毕
                                }
                        }
                        listener.onDownloaded();//下载完成,调用onDownloaded()方法
        }
}
(4)编辑MainActivity.java文件,源代码如下:
public class MainActivity extends Activity
{
        private static final String TAG = "MainActivity";
        Button downloadBtn;//声明下载按钮
    @Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        downloadBtn = (Button)findViewById(R.id.download_btn);//找到id为download_btn的按钮
        downloadBtn.setOnClickListener(new OnClickListener()   
{//匿名内部类形式监听器
                        @Override
                        public void onClick(View v)
{
                                DownloadUtils.getInstance().download(new MyDownloadListener());
                        }
                });
    }
    //内部类形式使用自定义监听器
private final class MyDownloadListener implements DownloadListener
{
                @Override
                public void onDownloading(int progress)
{//下载中
                        Log.d(TAG, "正在下载,进度:" + progress);
                }
                @Override
                public void onDownloaded()
{//下载完成
                        Log.d(TAG, "下载完成");
                }
    }   
    @Override
public boolean onCreateOptionsMenu(Menu menu)
{
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}
(4)右击工程chapter7_3,在弹出的快捷菜单中选择Run As|Android Application命令,LogCat的日志信息如图7-7所示:

论坛徽章:
0
13 [报告]
发表于 2013-04-15 15:33 |只看该作者
本帖最后由 didimm 于 2013-04-15 15:35 编辑

7.5  基于回调的事件处理
前面的章节当中,笔者已经介绍了如何使用基于监听器的事件处理机制,并通过实例向读者朋友们详细介绍了如何使用监听器来监听和处理用户单击的事件以及键盘的按下和释放事件。本节当中,笔者将向读者介绍如何使用基于回调的事件处理机制。
7.5.1 创建自定义视图
由于基于回调的事件处理机制,是当用户在GUI组件上触发某事件时,由该组件自身特定的函数负责处理该事件。因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。
View类是Android的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘图的画布,这个画布可以进行任意扩展。在游戏开发中往往需要自定义视图(View),这个画布的功能更能满足游戏开发中的需要。在Android中,任何一个View类都只需重写onDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本形式等。下面通过实例的方法来向读者朋友们介绍如何创建自定义视图。
(1)新建工程chapter7_4,新建一个继承自android.view.View的自定义视图类MyView,编辑MyView.java文件,源代码如下:
public class MyView extends View
{   
public MyView(Context context)
{  
        super(context);  
    }  
public MyView(Context context,AttributeSet attr)
{   
        super(context,attr);   
    }      
    private Paint myPaint;   //声明画笔对象
    private static final String myString1 = "中国移动互联网行业各年度投资情况";   
    private static final String myString2 = "来源:清科研究中心 2011.08";   
    @Override   
protected void onDraw(Canvas canvas)
{   
        // TODO Auto-generated method stub   
        super.onDraw(canvas);  
        myPaint = new Paint();   
        //绘制标题   
        myPaint.setColor(Color.BLACK); //设置画笔颜色   
        myPaint.setTextSize(1;//设置文字大小   
        canvas.drawText(myString1, 20, 20, myPaint);   
        //绘制坐标轴   
        canvas.drawLine(50, 100, 50, 500, myPaint);//纵坐标轴         
        canvas.drawLine(50, 500, 400, 500, myPaint);//横坐标轴   
        int[] array1 = new int[]{0, 50, 100, 150, 200, 250, 300, 350};  
        //绘制纵坐标刻度   
        myPaint.setTextSize(10);//设置文字大小   
        canvas.drawText("单位:百万美元", 20, 90, myPaint);   
        for (int i = 0; i < array1.length; i++)
{  
            canvas.drawLine(50, 500 - array1, 54, 500 - array1, myPaint);  
            canvas.drawText(array1 + "", 20, 500 - array1, myPaint);  
        }  
        //绘制横坐标文字   
        String[] array2 = new String[]{"2008年", "2009年", "2010年", "2011上半年"};  
        for (int i = 0; i < array2.length; i++)
{  
            canvas.drawText(array2, array1 + 80, 520, myPaint);  
        }  
        //绘制条形图   
        myPaint.setColor(Color.BLUE); //设置画笔颜色   
        myPaint.setStyle(Style.FILL); //设置填充   
        canvas.drawRect(new Rect(90, 500 - 56, 110, 500), myPaint);//画一个矩形,前两个参数是矩形左上角坐标,后两个参数是右下角坐标           
        canvas.drawRect(new Rect(140, 500 - 98, 160, 500), myPaint);//第二个矩形        
        canvas.drawRect(new Rect(190, 500 - 207, 210, 500), myPaint);//第三个矩形      
        canvas.drawRect(new Rect(240, 500 - 318, 260, 500), myPaint);//第四个矩形      
        //绘制出处   
        myPaint.setColor(Color.BLACK); //设置画笔颜色   
        myPaint.setTextSize(16);//设置文字大小   
        canvas.drawText(myString2, 20, 560, myPaint);   
    }
}
为了实现自定义View,需要创建一个新的类,然后重写onDraw方法,在此需要注意,新创建的类MyView要继承View基类,同时还要加入有参数的两个构造方法MyView(Context context)和MyView(Contextcontext,AttributeSet attr),否则编译运行无法通过。
(2)编辑res/layout/activity_main.xml文件,源代码如下:
<?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"  
    androidrientation="vertical" >  
    <com.example.chapter7_4.MyView  
        android:layout_width="fill_parent"  
           android:layout_height="wrap_content"  
           android:focusableInTouchMode="true"
        android:background="#FFFFFF"/>  
</LinearLayout>  
其中android:focusableInTouchMode=”true”,可以使得自定义视图在触摸模式下获取用户焦点。
(3)右击工程chapter7_4,在弹出的快捷菜单中选择Run As|Android Application命令,运行效果如图7-8所示

6.png (17.21 KB, 下载次数: 26)

6.png

论坛徽章:
0
14 [报告]
发表于 2013-04-15 15:37 |只看该作者
7.5.2 回调处理onKeyDown事件
对于基于回调方式的onKeyDown事件的处理,只需要重写android.view.View基类的onKeyDown()方法,源代码如下:
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
            if(KeyEvent.KEYCODE_MENU == keyCode){//如果菜单键被按下
                    Toast.makeText(getContext(), "菜单键被按下", Toast.LENGTH_LONG).show();
                    return true;//事件不会继续往下传播
            }
            return super.onKeyDown(keyCode, event);
    }
右击工程chapter7_4,在弹出的快捷菜单中选择Run As|Android Application命令,当触摸自定义视图控件过后,按下“菜单”键的运行效果如图7-9所示:

论坛徽章:
0
15 [报告]
发表于 2013-04-15 15:38 |只看该作者
7.5.3 回调处理onKeyUp事件
对于基于回调方式的onKeyUp事件的处理,也只需要重写android.view.View基类的onKeyUp()方法,源代码如下:
  @Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
              if(KeyEvent.KEYCODE_SEARCH== keyCode)
{//如果菜单键被释放
                    Toast.makeText(getContext(), "搜索键被释放", Toast.LENGTH_LONG).show();
                    return true;//事件不会继续往下传播
               }
            return super.onKeyUp(keyCode, event);
    }
右击工程chapter7_4,在弹出的快捷菜单中选择Run As|Android Application命令,当触摸自定义视图控件过后,释放“搜索”键时的运行效果如图7-10所示:

论坛徽章:
0
16 [报告]
发表于 2013-04-15 15:40 |只看该作者
本帖最后由 didimm 于 2013-04-15 15:41 编辑

7.5.4 回调处理触摸事件
智能机没有实体键盘,只有虚拟键盘,用户大部分的操作都是通过触摸屏幕来完成的。因此对于触摸事件的捕获与处理就显得格外的重要,用户可以利用智能机的触摸屏的特性完成各种各样的手势操作。几乎任何一款线上的Android的应用程序里面,都有相关的触摸手势操作。利用触摸滑动来完成操作的最典型的例子就是在大多数应用程序安装之后第一次启动过程当中,用户一般都可以通过向左或者向右滑动来进行一些优美图片的切换,引入这些图片的主要目的就是介绍当前版本应用程序的一些功能性的特点,这就是当前比较流行的“引导型”设计。下面来看一下虾米音乐的客户端程序安装之后第一次的启动过程。如图7-11和7-12,用户可以通过手指的滑动,切换不同的说明图片,当然虾米音乐的客户端程序的说明图片不止这两幅,笔者在这里只是简单举个例子,介绍一下。
客户端“引导型”设计图片简单扼要的说明了产品的主要功能和使用场景,使用户一目了然,非常清晰。不过对于这种“引导型”设计,有几点需要注意一下:
        告诉用户现在处于指南的哪个位置。
        每个页面只讲清楚一个功能。
        最好可以选择性的跳过。
        只能出现一次。

当用户界面组件被触摸到的时候,该组件的触摸(onTouch)事件会被回调,基于触摸事件。实际上真正触发的主要是三种不同的操作:
        第一种是MotionEvent.ACTION_DOWN,也就是手指刚刚碰到用户组件的时候。
        第二种是MotionEvent.ACTION_MOVE,也就是用户触摸用户组件的时候。有的时候,可能还要滑动的操作,这个时候实际上真正的事件操作是MotionEvent.ACTION_MOVE。
        第三种是MotionEvent.ACTION_UP,也就是用户手指离开用户组件的时候。
由于大部分触摸事件都是针对于程序当中定义的自定义View控件的,所以在此之前笔者并没有介绍如何通过监听器的方式对触摸事件进行监听和处理。下面笔者通过实例的方式来为读者朋友们介绍如何通过重写自定义View控件的onTouchEvent()方法来对用户的触摸事件进行监听和处理。
(1)新建工程chapter7_5,新建自定义视图类CustomView,编辑CustomView.java文件,源代码如下:
public class CustomView extends View
{
        Paint mPaint;// 声明画笔对象
        List<Dot> dots;// 点集合
        public CustomView(Context context)
{
                super(context);
                init();
        }
        public CustomView(Context context, AttributeSet attrs)
{
                super(context, attrs);
                init();
        }
         public void init()
{
                mPaint = new Paint();
                mPaint.setColor(Color.RED);   //设置绘制的颜色是红色
                mPaint.setAntiAlias(true);                
                setBackgroundColor(Color.BLUE);        //视图对象背景色是蓝色      
                dots = new ArrayList<CustomView.Dot>();  //初始化时里面没有显示任何的红点
            }
           @Override
            protected void onDraw(Canvas canvas)
{                
                for(Dot dot : dots)
{ //绘制所有视图对象里保存的Dot点信息
                    canvas.drawCircle(dot.x, dot.y, dot.radius, mPaint);
                }
            }
          @Override
            public boolean onTouchEvent(MotionEvent event)
{
                float x = event.getX();//获取随机点击位置的X坐标值
                float y = event.getY();//获取随机点击位置的Y坐标值  
                float radius = (float) (1 + Math.random() * 9); //生成一个随机半径值范围是1 - 10
                //将点击的坐标和随机生成的半径值构造成Dot对象存放到视图里
                dots.add(new Dot(x,y,radius));
                invalidate();//调用onDraw()重绘View控件
                return super.onTouchEvent(event);
            }
        static class Dot
{
                public float x;
                public float y;
                public float radius;
                public Dot(float x, float y, float radius)
{
                        this.x = x;
                        this.y = y;
                        this.radius = radius;
                }
        }
}

9.png (115.63 KB, 下载次数: 25)

9.png

论坛徽章:
0
17 [报告]
发表于 2013-04-15 15:43 |只看该作者
(2)编辑res/layout/activity_main.xml文件,源代码如下:
<?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"    androidrientation="vertical" >
      <com.example.chapter7_5.CustomView
        android:layout_width="fill_parent"  
            android:layout_height="fill_parent"  
                android:focusableInTouchMode="true"
        android:background="#FFFFFF"/>  
</LinearLayout>  
(3)右击工程chapter7_5,在弹出的快捷菜单中选择Run As|Android Application命令,在屏幕上触摸几次过后的效果如图7-13所示:

7.5.5 Android的手势识别
        除了能够对简单的触摸事件进行处理之外,为了能够提高应用程序的用户体验,有的时候应用程序还需要能够识别用户的手势,根据用户不同的手势去完成不同的操作。开发者只需要继承SimpleOnGestureListener类,然后重载感兴趣的手势即可。下面通过实例来为读者朋友们介绍如何在自定义View当中对用户手势进行识别。
        (1)新建工程chapter7_6,新建一个继承自SimpleOnGestureListener的MyGestureListener类,编辑MyGestureListener.java文件,源代码如下:
public class MyGestureListener extends SimpleOnGestureListener
{
           private Context mContext; //声明上下文对象             
            MyGestureListener(Context context)
{
                mContext = context;
            }
            @Override
            public boolean onDown(MotionEvent e)
{ // 单击,触摸屏按下时立刻触发
                Toast.makeText(mContext, "DOWN " + e.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public void onShowPress(MotionEvent e)
{ // 短按,触摸屏按下后片刻后抬起,会触发这个手势,如果迅速抬起则不会
                Toast.makeText(mContext, "SHOW " + e.getAction(), Toast.LENGTH_SHORT).show();            
            }
            @Override
            public boolean onSingleTapUp(MotionEvent e)
{ // 抬起,手指离开触摸屏时触发(长按、滚动、滑动时,不会触发这个手势)
                Toast.makeText(mContext, "SINGLE UP " + e.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                    float distanceX, float distanceY)
{ //滚动,触摸屏按下后移动
                Toast.makeText(mContext, "SCROLL " + e2.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public void onLongPress(MotionEvent e)
{ //长按,触摸屏按下后既不抬起也不移动,过一段时间后触发
                Toast.makeText(mContext, "LONG " + e.getAction(), Toast.LENGTH_SHORT).show();
            }
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                    float velocityY)
{ // 滑动,触摸屏按下后快速移动并抬起,会先触发滚动手势,跟着触发一个滑动手势
                Toast.makeText(mContext, "FLING " + e2.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public boolean onDoubleTap(MotionEvent e)
{ //双击,手指在触摸屏上迅速点击第二下时触发
                Toast.makeText(mContext, "DOUBLE " + e.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public boolean onDoubleTapEvent(MotionEvent e)
{ // 双击的按下跟抬起各触发一次
                Toast.makeText(mContext, "DOUBLE EVENT " + e.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e)
{ //单击确认,即很快的按下并抬起,但并不连续点击第二下
                Toast.makeText(mContext, "SINGLE CONF " + e.getAction(), Toast.LENGTH_SHORT).show();
                return false;
            }
}

论坛徽章:
0
18 [报告]
发表于 2013-04-15 15:44 |只看该作者
(2)创建一个自定义视图MyView,编辑MyView.java文件,源代码如下:
public class MyView extends View
{
        private GestureDetector mGestureDetector; // 声明手势监听者
        public MyView(Context context)
{
                super(context);
                init(context);
        }
        public MyView(Context context, AttributeSet attrs)
{
                super(context, attrs);
                init(context);
        }
        private void init(Context context)
{
                mGestureDetector = new GestureDetector(context, new MyGestureListener(context));//实例化手势监听者
                setLongClickable(true);//View必须设置longClickable为true,否则手势识别无法正确工作,只会返回Down, Show, Long三种手势
                this.setOnTouchListener(new OnTouchListener()
{
                        public boolean onTouch(View v, MotionEvent event)
{
                                return mGestureDetector.onTouchEvent(event);//采用手势监听者来识别用户手势
                        }
           });}
}
对于自定义View,如果要使用手势识别的话,有两处地方必须注意:
1:View必须设置longClickable为true,否则手势识别无法正确工作,只会返回Down, Show, Long三种手势 。
2:必须在View的onTouchListener中调用手势识别,而不能直接覆盖onTouchEvent方法,否则同样手势识别无法正确工作。
(3)编辑res/layout/activity_main.xml文件,源代码如下:
<?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"  
    androidrientation="vertical" >  
    <com.example.chapter7_6.MyView
        android:layout_width="fill_parent"  
            android:layout_height="fill_parent"  
                android:focusableInTouchMode="true"
        android:background="#FF0000"/>  
</LinearLayout>  
(4)右击工程chapter7_6,在弹出的快捷菜单中选择Run As|Android Application命令,笔者单击确认很快按下并抬起后效果如图7-14所示:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP