[Android]
Android系统编程入门系列之界面Activity交互响应
移动开发
发布于:2021-07-17 09:31
|
阅读数:318
|
评论:0
|
在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应。本文将针对这两种用户交互方式分别展开介绍。
界面内交互
界面响应
说到界面交互,很容易想到用户在设备屏幕上的触摸操作。可是屏幕那么大要怎么确定用户触摸的位置呢?Android系统定义了一套屏幕坐标规则,该规则不仅适用于当前的屏幕交互,在后文提及的动画绘制及其他屏幕相关操作等都同样适用。该规则将屏幕的左上角作为屏幕坐标的原点,从左上角往右上角延伸的方向作为屏幕坐标的x轴,从左上角往左下角延伸的方向作为屏幕坐标的y轴。
比如针对一款 1024x512 尺寸的TV设备,其左下角的屏幕坐标值为 (0, 512),右下角的屏幕坐标值为 (1024, 512),右上角的屏幕坐标值为 (1024, 0),左上角的屏幕坐标值为 (0, 0)。
对屏幕的触摸位置有了衡量标准,是不是就可以根据不同的位置做触摸操作了呢?说到触摸操作,也需要细化之后单独处理。Android系统将用户操作行为,大致分为三种:按下行为,滑动行为,抬起释放行为。这样系统就可以根据每一个操作行为做单独的响应处理了。
另外,用户的操作对象,除了上文提到的硬件设备屏幕以外,还有硬件设备的按键(包括硬件按键和虚拟按键)。只不过对按键的操作行为只有按下行为和抬起释放行为两种,而且按键的操作不需要用到屏幕坐标相关内容。
基于上文的介绍,可以在界面Activity中可以分别重写下边三个方法对用户的界面操作交互做出响应。
- boolean onTouchEvent(MotionEvent event)
在子视图没有处理的情况下,用户对硬件设备屏幕的每一个操作,都会回调一次该方法。
其参数android.view.MotionEvent事件类的实例化对象event。
event.getAction()方法可以获取当前事件行为,包括MotionEvent.ACTION_DOWN按下行为、MotionEvent.ACTION_MOVE滑动行为、MotionEvent.ACTION_UP抬起释放行为等。
event.getX()方法获取当前操作的屏幕坐标x轴值。
同理event.getY()方法获取当前操作的屏幕坐标y轴值。
- boolean onKeyDown(int keyCode, KeyEvent event)
在子视图没有处理的情况下,用户对硬件设备按键的每一次按下行为,都会回调一次该方法。
参数一int类型的keyCode指定按键类型,一般其值与参数二event.getKeyCode()相等。
参数二android.view.KeyEvent类的实例化对象event。
event.getAction()方法同样可以获取当前事件行为,只有KeyEvent.ACTION_DOWN按下行为和KeyEvent.ACTION_UP抬起释放行为两个行为值。
event.getKeyCode()方法可以获取触发当前事件的按键类型,其值包括KeyEvent.KEYCODE_HOMEHOME键,KeyEvent.KEYCODE_POWER电源键,KEYCODE_VOLUME_UP音量增加键等。
- boolean onKeyUp(int keyCode, KeyEvent event)
在子视图没有处理的情况下,用户对硬件设备按键的每一次抬起释放行为,都会回调一次该方法。其两个参数与上述onKeyDown()中的两个参数类似。
视图响应
相对来说,界面内的视图响应要繁琐一些,而能实现的效果也更多样化。当把视图View作为用户的操作对象时,仍然可以重写上述界面响应的三个方法,但是系统视图往往也封装了一层更加简单粗暴的响应方法。
在视图中重写界面响应的三个方法后,如果返回的结果为true,则上文界面响应中的三个方法将不会被回调。
为什么需要封装一层响应方法呢?用户对视图的操作,往往就是点击(短时间内执行按下行为和抬起释放行为),长按(在执行按下行为后等待一段时间再执行抬起释放行为),拖拽(在执行按下行为后执行一段滑动行为之后再执行抬起释放行为)这些固定操作类型。如果每个视图都要细分用户的操作行为,就会有大量冗余的操作类型判断代码,所以AndroidSDK定义了一系列接口分别对应用户的操作类型。视图如果需要响应某个操作,只需要设置其操作类型接口的实例化对象,并在该对象中实现相关方法即可。而这些接口主要有以下三个。
- View.OnClickListener接口
需要实现onClick(View view)方法,在该方法内响应响应视图View被用户点击后的代码逻辑。
- View.OnLongClickListener接口
需要实现onLongClick(View view)方法,在该方法内响应响应视图View被用户长按后的代码逻辑。
- View.OnDragListener接口
需要实现onDrag(View v, DragEvent event)方法,在该方法内响应视图View被用户拖拽后的代码逻辑。
另外,不同的系统视图也可能有单独设置的响应方法,或者自定义视图也会提供单独的响应方法,例如列表视图中的某一行数据被单独点击后如何响应,这些都要根据具体的视图类查找并使用对应的响应方法,这里不再赘述。
事件传递机制
在上文界面响应的三个方法中,关于他们被回调的时机,有个前提是子视图没有处理,即子视图的界面响应方法返回结果为false。这就涉及到Android系统的事件传递机制了。
我们知道界面Activity在创建之后会调用setContentView(int layoutId)加载根视图View,而根视图里边则可以内嵌一层层的子视图。那么,如果用户将手指触摸到屏幕上,会触发按下行为,该行为作为事件首先传递到根视图中,之后根视图再将该事件传递给子视图,子视图再将该事件传递给子视图的子视图,这样按照加载时的嵌套顺序一层层传递事件,称之为事件分发。
直到该事件传递到最后一层子视图,或者某一层视图不再继续传递该事件,那么该事件将在最后传递到的这层视图中被首先处理。而每层视图在收到传递进来的事件后,都有两条路可以选择,要么将该事件继续传递给子视图,要么自己处理该事件,如果选择第二条路不再继续传递子视图而是自己处理该事件,称之为事件拦截。
一旦某层视图处理了该事件,那么其父层视图将继续处理该事件,之后是父层的父层视图处理该事件,事件被这样一层层处理,直到根视图处理该事件结束,称之为事件处理。
在经历了事件分发和事件处理之后,这样的一个事件传递机制就算完成了。而上文提到的每一个事件,都是如此。
上述过程在代码中的实现,只需要针对事件分发、事件拦截和事件处理分别定义一个可重写的方法即可。能够重写该方法的位置主要是android.app.Acitivty和android.view.View中,由于事件拦截只会发生在子视图的传递过程中,在界面中并不需要,所以事件拦截对应的方法只在android.view.GroupView中重写。
- boolean dispatchTouchEvent (MotionEvent event)
当某个事件被分发到该视图时,系统回调视图中的该方法。返回结果表示当前事件是否被处理。
- boolean onInterceptTouchEvent(MotionEvent event)
当某个事件被分发到该视图后,系统会回调视图中的该方法,根据其返回结果判断是否拦截该事件交由当前视图处理。默认返回结果为false,表示不拦截该事件,将会继续回调子视图的dispatchTouchEvent()。返回结果为true时,表示拦截该事件,将会回调当前视图的onTouchEvent().
- boolean onTouchEvent (MotionEvent event)
当某个事件轮到该视图被处理时,系统会回调视图中的该方法。返回结果表示当前事件是否被处理。
界面间交互
上文介绍了针对一个界面Activity的交互响应,那么两个界面Activity之间如何交互呢?这就用到在加载界面一文中启动Activity所使用的android.content.Intent意图类了。不同于用户与界面的交互,界面间交互主要是变量数据的共享,所以通过Intent支持的交互数据类型是有限的。
发送数据界面
在启动一个界面Activity之前要先创建意图对象,在该意图对象调用putExtras(Bundle bundle)方法,可以将要发送的数据打包成android.os.Bundle类型的实例存入。
而该Bundle对象可以存储的数据类型支持包括boolean、char、byte、short、int、float、double、long八种基本数据类型,String类型和实现Parcelable接口的任意类型,及其[]数组或ArrayList数组,和其他一些不常用类型。这些数据都是以key-value键值对的形式保存在Bundle对象中。对于要保存的不同数据类型,分别调用对应的putT(String key, T value)系列方法即可以参数一key和参数二value的形式存入,同样可以调用对应的getT(String key)系列方法取出指定参数一key对应的value数据,这里的T泛指支持的不同数据类型。
另外也可以在创建的意图对象中直接调用putExtra(String key, T value)系列方法,将要发送的数据直接以key-value键值对的形式存入,同样也可以使用getTExtra(String key)系列方法取出指定参数一key对应的value数据,这里的T同样泛指Bundle可支持的不同数据类型。
在打包所有的数据后,就可以在当前界面Activity中继续调用startActivity(Intent intent)系列方法启动Intent意图参数中指定的另一界面Activity了。
这里的startActivity(Intent)方法是最简单的启动方法,另外还有startActivity(Intent, Bundle)在启动时将要发送的数据打包作为参数二传入。
或者startActivityForResult(Intent intent, int requestCode)在启动时传入一个唯一值作为参数二,以区分启动不同界面的意图,在启动的界面Activity返回后,系统会调用当前界面Activity中的onActivityResult(int requestCode, int resultCode, Intent data)方法,因此可以重写该方法。并根据参数一的唯一性对之前启动的不同界面意图做区分处理。参数二是根据启动界面不同关闭状态所返回的结果值,默认为android.app.Activity.RESULT_CANCELED,另外也可以为android.app.Activity.RESULT_FIRST_USER和android.app.Activity.RESULT_OK,其值需要在启动界面返回时设置。参数三是从启动界面返回的Intent类型,主要使用其中的Bundle打包数据类型对象,同样其值可以在启动界面返回时设置。
接收数据界面
作为接收数据的启动界面Activity,在其绑定上下文环境之后,一般是在onCreate(Bundle savedInstanceState)方法中,可以使用getIntent()方法获取传递进来的Intent意图对象,获取该对象之后自然就可以通过getBExtras()或一系列getTExtra(String key)获取到打包的数据,这样在启动界面中就可以使用在启动之前上一个界面Activtiy中的变量数据了。
而当启动界面Activity在被用户操作返回时,系统将回调该启动界面的onBackPressed()方法,之后将该Activity从栈中移出并销毁。所以可以重写onBackPressed()方法,在该方法中调用setResult(int resultCode, Intent data)设置上文提到的返回时参数。
或者在启动界面Activity代码中也可以主动调用finish()方法,以关闭当前界面。因此在调用finish()方法之前先调用setResult(int resultCode, Intent data)设置返回参数即可。
|
免责声明:
1. 本站所有资源来自网络搜集或用户上传,仅作为参考不担保其准确性!
2. 本站内容仅供学习和交流使用,版权归原作者所有!© 查看更多
3. 如有内容侵害到您,请联系我们尽快删除,邮箱:kf@codeae.com
|
|
|
|
|