【Android UI】捕捉输入控件事件

2024-06-06 04:18

本文主要是介绍【Android UI】捕捉输入控件事件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

原文自:http://android.eoe.cn/topic/ui

 

在Android中有多种方法可以用来拦截用户与程序的交互事件。如果想处理用户界面中触发的事件,可以通过从用户交互的View捕获事件来实现。View这个类提供了这些方法。

在用来构成布局的各种View类中,我们可以看到有几个用于UI事件的公共回调方法。当这些对象中有用户行为产生时,Android框架就会调用相应的回调方法。例如,当一个view(比如一个按钮Button)被触摸了,那么它的onTouchEvent()方法就会被调用。但是,为了拦截到这个事件,你必须扩展这个类并重写这些方法。然而,为了处理这样一个事件就扩展每一个View对象是不实际的。这就是为什么View类还提供了包含一些很方便定义的回调方法的嵌套接口的原因。这些叫做事件监听器(event listener)接口就是你拦截UI交互事件的入口。

虽然多数情况下使用事件监听器来监听用户交互,但是有时候为了创建一个自定义的组件,也需要扩展一个View类。比如你可能想要扩展一个Button类来使它更好用。这种情况下,你就可以使用事件处理器(event handler)来定义默认的事件行为。

事件监听器

一个事件监听器是View类中一个包含单一回调方法的接口。当注册了监听器的View发生了跟监听器对应的UI交互事件时,Android框架就会调用这些回调方法。

事件监听器接口中包含了以下回调方法:

onClick()

:来自View.OnClickListener接口。当用户触摸了一个对象(在触摸模式下),或者通过导航键或轨迹球使它获得焦点后再按下兼容"enter"的按键或是按下轨迹球,这个方法被调用。

onLongClick()

:来自View.OnLongClickListener接口。当用户在一个对象上触摸并按住不放(触摸模式下),或者通过导航键或轨迹球使它获得焦点后再按下兼容"enter"的按键或是轨迹球并按住不放(一秒钟时间),这个方法被调用。

onFocusChange()

:来自View.OnFocusChangeListener。当用户使用导航键或者轨迹球导航到一个对象或离开一个对象时,这个方法被调用。

onKey()

:来自View.OnKeyListener接口。当用户让焦点落在一个对象上后按下或释放设备上的一个键时,这个方法被调用。

onTouch()

:来自View.OnTouchListener接口,当用户执行一个触屏事件的动作时,包括按下动作、释放动作,或者任何在屏幕上的手势(当然必须在对象所在的区域内),这个方法被调用。

onCreateContextMenu()

:来自View.OnCreateContextMenuListener接口。当一个上下文菜单被创建(长按后的结果)时,这个方法被调用。关于上下文菜单的更多讨论,请参考关于Menus | 菜单 - Menus的开发指南。

这些方法是各自接口的唯一成员。如果要定义这些方法来处理事件,就要在Activity中实现这些嵌套接口,或者定义一个匿名内部类。然后,把你实现的实例传递给对应的View.set…Listener()方法。(例如,以实现的OnClickListener作为参数调用setOnClickListener()方法)。

下面的例子演示了如何给一个Button注册一个on-click监听器:

// 创建一个实现了OnClickListener的匿名内部类的对象
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};

protected void onCreate(Bundle savedValues) {
...
// 从布局中找到需要的按钮
Button button = (Button)findViewById(R.id.corky);
// 用上面实现的对象注册点击监听器
button.setOnClickListener(mCorkyListener);
...
}

你可能也发现把OnClickListener作为Activity的一部分来实现会更方便。这样可以避免额外的类加载和对象内存分配。如:

public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
...
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}

1
2
3
4
5
// 实现OnClickListener的回调
public void onClick(View v) {// 这里做按钮点击后需要做的事情
}
...

}

注意上例中的onClick()回调方法没有返回值,但是有些其他的事件监听器方法必须要返回一个布尔值。具体情况取决于事件。以下是针对部分情况进行说明:
* onLongClick() - 这个方法返回一个布尔值,用来指明这个事件是否已经被你消耗(使用)了而不应进一步传递。也就是说,如果返回true,表明你已经处理了这个事件,并且事件应该就此停止;如果返回false,表明你没有处理这个事件,并且/或者这个事件应该继续传递给其他的on-click监听器来处理。
* onKey() - 这个方法返回一个布尔值,用来指明这个事件是否已经被你消耗了而不应进一步传递。也就是说,如果返回true,表明你已经处理了这个事件,并且事件应该就此停止;如果返回false,表明你没有处理这个事件,并且/或者这个事件应该继续传递给其他的on-key监听器来处理。
* onTouch() - 这个方法返回一个布尔值,用来指明你的监听器是否消耗这个事件。重要的是这个事件可能包含多个彼此跟随的动作。因此,如果在接收到按下动作事件时返回了false,表明你不使用这个事件,并且对这个事件中按下动作的后续动作也不感兴趣了。这样的话,你将不会再为这个事件中的任何其他动作调用这个方法,比如手势或者结束动作事件。

记住,硬件按键事件始终是发送给当前焦点所在的View。它们从View层次结构的最顶层开始从上而下派发,直到到达合适的目标。如果你当前的View(或View的子视图)有焦点,那么通过dispatchKeyEvent()方法你能够看到事件的派发路线。通过View捕获按键事件的另一个方法是,你可以在Activity内部通过onKeyDown()和onKeyUp()两个方法来接受所有的按键事件。

而且,当考虑到程序的文本输入的时候,请注意许多设备只有软键盘输入法。这些输入法不要求必须有实体按键;一些设备可能使用语音输入、手写输入等等。即使一个输入法展现了像实体键盘一样的界面,通常它也不会触发onKeyDown()一类的事件。你永远不应该让你的UI依赖特定的按键来实现操作,除非你想将你的程序限制在拥有实体键盘的设备上。尤其,不要依赖在这些按键上按下return键来确认输入;而应该用IME_ACTION_DONE一类的动作来表示输入法完成了程序中你想要的动作,以便程序用应有的方式来改变UI。不用去猜测软键盘工作的方式,只相信它会为程序提供格式化的文本就够了。

注意:Android会首先调用事件处理器,然后再调用类定义的合适的默认处理程序。这样,如果这些事件监听器返回了true,那么事件向其他事件监听器的传递会被中止,View中默认的事件处理程序的回调也会被阻止。因此,当你却确信要中止一个事件的时候才返回true。

事件处理器

如果你要从View构建一个自定义的组件,你可以定义几个回调方法作为默认的事件处理器。在Custom Components | 自定义组件 - Custom Components文档中,你可以学到一些用来处理事件的常用回调,包括:
* onKeyDown(int, KeyEvent) - 当新的按键事件产生的时候调用
* onKeyUp(int, KeyEvent) - 当一个按键松开事件产生的时候调用
* onTrackballEvent(MotionEvent) - 当轨迹球滚动的时候调用
* onTouchEvent(MotionEvent) - 当触屏动作产生时调用
* onFocusChanged(boolean, int, Rect) - 当View获取或者失去焦点的时候调用
另外还有一些需要注意的方法,它们不属于View类,但是能够直接影响到你处理事件的方式。因此,当你管理布局中更复杂的事件的时候,考虑下面这些方法:
* Activity.dispatchTouchEvent(MotionEvent) - 这个方法允许Activity在触屏事件被传递到window之前拦截它们。
* ViewGroup.onInterceptTouchEvent(MotionEvent) - 这个方法允许ViewGroup查看传递到它的子view的触屏事件。
* ViewParent.requestDisallowInterceptTouchEvent(boolean) - 在父View中调用这个方法来表明它不应该使用onInterceptTouchEvent(MotionEvent)来拦截触屏事件。

触摸模式

当用户使用方向键或者轨迹球浏览到一个用户界面的时候,就需要把焦点交给可交互的对象(比如按钮)以便用户能够看到这些对象能够接受输入。但是,如果一个设备支持触摸,并且用户通过触摸来实现交互,那么就不必高亮显示这些对象或者把焦点交给某个View了。这样,就有了一个名为触摸模式的交互模式了。

对一个支持触摸的设备,一旦用户触摸了屏幕,设备就进入了触摸模式。从此,只要一个View的isFocusableInTouchMode()方法返回值为true,那它就是可以获得焦点的,比如一个文本编辑框。其他可以触摸的View比如按钮,在被触摸的时候是不会获得焦点的;它们仅仅是在按下的时候触发一下它们on-click监听器。

每当用户点击了一个方向键或者滚动轨迹球的时候,设备就将退出触摸模式,并寻找一个View让其获得焦点。现在,用户就恢复到了不需要触摸屏的交互模式了。

触摸模式的状态是整个系统维护的(所有的窗口和活动视图)。要查看当点设备所处的触摸模式状态,可以调用isInTouchMode()方法得到当前设备是否处于触摸模式。

处理焦点

Android框架会处理焦点的移动来响应用户的输入,包括当View被删除或隐藏,或者新的View变得可见时的焦点变化。View通过isFocusable()方法来表明它们是否希望获得焦点。通过调用setFocusable()方法来设置一个View能否获得焦点。在触摸模式下,你通过isFocusableInTouchMode()方法查询一个View是否允许获得焦点。当然你可以通过调用setFocusableInTouchMode()方法来改变设置。

焦点的移动是基于一种在特定方向查找最近的可接受焦点的View的算法。在某些不常见的情况下,这种默认的算法找到的焦点可能与开发者的期望表现不一致。这时,你就要在下面的布局文件中的xml属性来精确指定焦点的移动:nextFocusDown, nextFocusLeft, nextFocusRight, 以及 nextFocusUp。给将要失去焦点的View添加一个上面的属性,在属性值中定义下一个将要获得焦点的View的id。比如:




通常,在这样一个垂直布局中,从第一个按钮向上浏览不会到任何地方,同样从第二个按钮向下浏览也不会到任何地方。现在,top按钮定义下一个向上导航的焦点获得者为bottom按钮(反之亦然),这样焦点就可以在这两个按钮之间上下循环了。

如果你习惯在UI中声明一个默认拥有焦点的View(通常不这样做),就需要在布局声明文件中给这个View添加一个android:focusable属性并把这个属性值设置为true。你也可以在触摸模式中使用android:focusableInTouchMode属性来定义默认拥有焦点的View。

要强制让某个View获得焦点,调用它的requestFocus()方法。

 

就像上面“事件监听器”章节讨论的一样,使用onFocusChange()方法来监听焦点变化事件(当一个View获取到或者失去焦点的时候会发出通知)。

这篇关于【Android UI】捕捉输入控件事件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1035065

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使