androidcss button按钮样式响应点击事件方式有哪两种方式

简单讲解Android开发中触摸和点击事件的相关编程方法
投稿:goldensun
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android开发中触摸和点击事件的相关编程方法,包括事件侦听器等安卓开发中常用的接口的基本使用方法,需要的朋友可以参考下
在Android上,不止一个途径来侦听用户和应用程序之间交互的事件。对于用户界面里的事件,侦听方法就是从与用户交互的特定视图对象截获这些事件。视图类提供了相应的手段。
在各种用来组建布局的视图类里面,你可能会注意到一些公共的回调方法看起来对用户界面事件有用。这些方法在该对象的相关动作发生时被Android框架调用。比如,当一个视图(如一个按钮)被触摸时,该对象上的onTouchEvent()方法会被调用。不过,为了侦听这个事件,你必须扩展这个类并重写该方法。很明显,扩展每个你想使用的视图对象(只是处理一个事件)是荒唐的。这就是为什么视图类也包含了一个嵌套接口的集合,这些接口含有实现起来简单得多的回调函数。这些接口叫做事件侦听器event listeners,是用来截获用户和你的界面交互动作的"门票"。
当你更为普遍的使用事件侦听器来侦听用户动作时,总有那么一次你可能得为了创建一个自定义组件而扩展一个视图类。也许你想扩展按钮Button类来使某些事更花哨。在这种情况下,你将能够使事件处理器event handlers类来为你的类定义缺省事件行为。
事件侦听器Event Listeners
事件侦听器是视图View类的接口,包含一个单独的回调方法。这些方法将在视图中注册的侦听器被用户界面操作触发时由Android框架调用。下面这些回调方法被包含在事件侦听器接口中:
onClick():包含于View.OnClickListener。当用户触摸这个item(在触摸模式下),或者通过浏览键或跟踪球聚焦在这个item上,然后按下"确认"键或者按下跟踪球时被调用。
onLongClick():包含于View.OnLongClickListener。当用户触摸并控制住这个item(在触摸模式下),或者通过浏览键或跟踪球聚焦在这个item上,然后保持按下"确认"键或者按下跟踪球(一秒钟)时被调用。
onFocusChange():包含于View.OnFocusChangeListener。当用户使用浏览键或跟踪球浏览进入或离开这个item时被调用。
onKey():包含于View.OnKeyListener。当用户聚焦在这个item上并按下或释放设备上的一个按键时被调用。
onTouch():包含于View.OnTouchListener。当用户执行的动作被当做一个触摸事件时被调用,包括按下,释放,或者屏幕上任何的移动手势(在这个item的边界内)。
onCreateContextMenu():包含于View.OnCreateContextMenuListener。当正在创建一个上下文菜单的时候被调用(作为持续的"长点击"动作的结果)。
这些方法是它们相应接口的唯一"住户"。要定义这些方法并处理你的事件,在你的活动中实现这个嵌套接口或定义它为一个匿名类。然后,传递你的实现的一个实例给各自的View.set...Listener() 方法。(比如,调用setOnClickListener()并传递给它你的OnClickListener实现。)
下面的例子说明了如何为一个按钮注册一个点击侦听器:
// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
protected void onCreate(Bundle savedValues) {
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
你可能会发现把OnClickListener作为活动的一部分来实现会便利的多。这将避免额外的类加载和对象分配。比如:
public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
// Implement the OnClickListener callback
public void onClick(View v) {
// do something when the button is clicked
注意上面例子中的onClick()回调没有返回值,但是一些其它事件侦听器必须返回一个布尔值。原因和事件相关。对于其中一些,原因如下:
onLongClick() – 返回一个布尔值来指示你是否已经消费了这个事件而不应该再进一步处理它。也就是说,返回true 表示你已经处理了这个事件而且到此为止;返回false 表示你还没有处理它和/或这个事件应该继续交给其他on-click侦听器。
onKey() –返回一个布尔值来指示你是否已经消费了这个事件而不应该再进一步处理它。也就是说,返回true 表示你已经处理了这个事件而且到此为止;返回false 表示你还没有处理它和/或这个事件应该继续交给其他on-key侦听器。
onTouch() - 返回一个布尔值来指示你的侦听器是否已经消费了这个事件。重要的是这个事件可以有多个彼此跟随的动作。因此,如果当接收到向下动作事件时你返回false,那表明你还没有消费这个事件而且对后续动作也不感兴趣。那么,你将不会被该事件中的其他动作调用,比如手势或最后出现向上动作事件。
记住按键事件总是递交给当前焦点所在的视图。它们从视图层次的顶层开始被分发,然后依次向下,直到到达恰当的目标。如果你的视图(或者一个子视图)当前拥有焦点,那么你可以看到事件经由dispatchKeyEvent()方法分发。除了从你的视图截获按键事件,还有一个可选方案,你还可以在你的活动中使用onKeyDown() and onKeyUp()来接收所有的事件。
注意: Android 将首先调用事件处理器,其次是类定义中合适的缺省处理器。这样,从这些事情侦听器中返回true 将停止事件向其它事件侦听器传播并且也会阻塞视图中的缺事件处理器的回调函数。因此当你返回true时确认你希望终止这个事件。
事件处理器Event Handlers
如果你从视图创建一个自定义组件,那么你将能够定义一些回调方法被用作缺省的事件处理器。在创建自定义组件Building Custom Components的文档中,你将学习到一些用作事件处理的通用回调函数,包括:
onKeyDown(int, KeyEvent) - 当一个新的按键事件发生时被调用。
onKeyUp(int, KeyEvent) - 当一个向上键事件发生时被调用。
onTrackballEvent(MotionEvent) - 当一个跟踪球运动事件发生时被调用。
onTouchEvent(MotionEvent) - 当一个触摸屏移动事件发生时调用。
onFocusChanged(boolean, int, Rect) - 当视图获得或者丢失焦点时被调用。
你应该知道还有一些其它方法,并不属于视图类的一部分,但可以直接影响你处理事件的方式。所以,当在一个布局里管理更复杂的事件时,考虑一下这些方法:
Activity.dispatchTouchEvent(MotionEvent) - 这允许你的活动可以在分发给窗口之前捕获所有的触摸事件。
ViewGroup.onInterceptTouchEvent(MotionEvent) - 这允许一个视图组ViewGroup 在分发给子视图时观察这些事件。
ViewParent.requestDisallowInterceptTouchEvent(boolean) - 在一个父视图之上调用这个方法来表示它不应该通过onInterceptTouchEvent(MotionEvent)来捕获触摸事件。
触摸模式Touch Mode
当用户使用方向键或跟踪球浏览用户界面时,有必要给用户可操作的item(比如按钮)设置焦点,这样用户可以知道哪个item将接受输入。不过,如果这个设备有触摸功能,而且用户通过触摸来和界面交互,那么就没必要高亮items,或者设定焦点到一个特定的视图。这样,就有一个交互模式 叫"触摸模式"。
对于一个具备触摸功能的设备,一旦用户触摸屏幕,设备将进入触摸模式。自此以后,只有isFocusableInTouchMode()为真的视图才可以被聚焦,比如文本编辑部件。其他可触摸视图,如按钮,在被触摸时将不会接受焦点;它们将只是在被按下时简单的触发on-click侦听器。任何时候用户按下方向键或滚动跟踪球,这个设备将退出触摸模式,然后找一个视图来接受焦点,用户也许不会通过触摸屏幕的方式来恢复界面交互。
触摸模式状态的维护贯穿整个系统(所有窗口和活动)。为了查询当前状态,你可以调用isInTouchMode() 来查看这个设备当前是否处于触摸模式中。
处理焦点Handling Focus
框架将根据用户输入处理常规的焦点移动。这包含当视图删除或隐藏,或者新视图出现时改变焦点。视图通过isFocusable()方法表明它们想获取焦点的意愿。
要改变视图是否可以接受焦点,可以调用setFocusable()。在触摸模式中,你可以通过isFocusableInTouchMode()查询一个视图是否允许接受焦点。你可以通过setFocusableInTouchMode()方法来改变它。焦点移动基于一个在给定方向查找最近邻居的算法。少有的情况是,缺省算法可能和开发者的意愿行为不匹配。在这些情况下,你可以通过下面布局文件中的XML属性提供显式的重写:nextFocusDown, nextFocusLeft, nextFocusRight, 和nextFocusUp。为失去焦点的视图增加这些属性之一。定义属性值为拥有焦点的视图的ID。比如:
&LinearLayout
android:orientation="vertical"
&Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
&Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
&/LinearLayout&
通常,在这个竖向布局中,从第一个按钮向上浏览或者从第二个按钮向下都不会移动到其它地方。现在这个顶部按钮已经定义了底部按钮为nextFocusUp (反之亦然),浏览焦点将从上到下和从下到上循环移动。
如果你希望在用户界面中声明一个可聚焦的视图(通常不是这样),可以在你的布局定义中,为这个视图增加android:focusable XML 属性。把它的值设置成true。你还可以通过android:focusableInTouchMode在触摸模式下声明一个视图为可聚焦。
想请求一个接受焦点的特定视图,调用requestFocus()。
要侦听焦点事件(当一个视图获得或者失去焦点时被通知到),使用onFocusChange(),如上面事件侦听器Event Listeners所描述的那样。
触摸事件、点击事件的区别
针对屏幕上的一个View控件,Android如何区分应当触发onTouchEvent,还是onClick,亦或是onLongClick事件?
在Android中,一次用户操作可以被不同的View按次序分别处理,并将完全响应了用户一次UI操作称之为消费了该事件(consume),那么Android是按什么次序将事件传递的呢?又在什么情况下判定为消费了该事件?
&&&&& 搞清楚这些问题对于编写出能正确响应UI操作的代码是很重要的,尤其当屏幕上的不同View需要针对此次UI操作做出各种不同响应的时候更是如此,一个典型例子就是用户在桌面上放置了一个Widget,那么当用户针对widget做各种操作时,桌面本身有的时候要对用户的操作做出响应,有时忽略。只有搞清楚事件触发和传递的机制才有可能保证在界面布局非常复杂的情况下,UI控件仍然能正确响应用户操作。
1.& onTouchEvent
&&&& onTouchEvent中要处理的最常用的3个事件就是:ACTION_DOWN、ACTION_MOVE、ACTION_UP。
&&&& 这三个事件标识出了最基本的用户触摸屏幕的操作,含义也很清楚。虽然大家天天都在用它们,但是有一点请留意,ACTION_DOWN事件作为起始事件,它的重要性是要超过ACTION_MOVE和ACTION_UP的,如果发生了ACTION_MOVE或者ACTION_UP,那么一定曾经发生了ACTION_DOWN。
&&&& 从Android的源代码中能看到基于这种不同重要性的理解而实现的一些交互机制,SDK中也有明确的提及,例如在ViewGroup的onInterceptTouchEvent方法中,如果在ACTION_DOWN事件中返回了true,那么后续的事件将直接发给onTouchEvent,而不是继续发给onInterceptTouchEvent。
2.& onClick、onLongClick与onTouchEvent
&&&& 曾经看过一篇帖子提到,如果在View中处理了onTouchEvent,那么就不用再处理onClick了,因为Android只会触发其中一个方法。这个理解是不太正确的,针对某个view,用户完成了一次触碰操作,显然从传感器上得到的信号是手指按下和抬起两个操作,我们可以理解为一次Click,也可以理解为发生了一次ACTION_DOWN和ACTION_UP,那么Android是如何理解和处理的呢?
&&&& 在Android中,onClick、onLongClick的触发是和ACTION_DOWN及ACTION_UP相关的,在时序上,如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能触发onClick或者onLongClick。主要的逻辑在View.java中的onTouchEvent方法中实现的:
case MotionEvent.ACTION_DOWN:
mPrivateFlags |= PRESSED;
refreshDrawableState();
if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
postCheckForLongClick();
case MotionEvent.ACTION_UP:
if ((mPrivateFlags & PRESSED) != 0) {
boolean focusTaken =
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
if (!mHasPerformedLongPress) {
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
if (!focusTaken) {
performClick();
&&&& 可以看到,Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的,performClick里会调用先前注册的监听器的onClick()方法:&&
public boolean performClick() {
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
LongClick的触发则是从ACTION_DOWN开始,由postCheckForLongClick()方法完成:&&
private void postCheckForLongClick() {
mHasPerformedLongPress =
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
可以看到,在ACTION_DOWN事件被捕捉后,系统会开始触发一个postDelayed操作,delay的时间在Eclair2.1上为500ms,500ms后会触发CheckForLongPress线程的执行:&&
class CheckForLongPress implements Runnable {
public void run() {
if (isPressed() && (mParent != null)
&& mOriginalWindowAttachCount == mWindowAttachCount) {
if (performLongClick()) {
mHasPerformedLongPress =
如果各种条件都满足,那么在CheckForLongPress中执行performLongClick(),在这个方法中将调用onLongClick():&&
public boolean performLongClick() {
if (mOnLongClickListener != null) {
handled = mOnLongClickListener.onLongClick(View.this);
从实现中可以看到onClick()和onLongClick()方法是由ACTION_DOWN和ACTION_UP事件捕捉后根据各种情况最终确定是否触发的,也就是说如果我们在一个Activity或者View中同时监听或者覆写了onClick(),onLongClick()和onTouchEvent()方法,并不意味着只会发生其中一种。&
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具从用户的角度,我希望完成这样的事情:
用户在主界面点击一个写有 “打开新的窗口” 字样的按钮,手机屏幕显示出一个新的窗口,并在这个窗口上显示 “我是另一个窗口”。
二:问题。上面的需求可以简化成这两个问题:
如何响应用户的点击事件?
如何打开另一个窗口(Activity)?
三:新建项目,如图:
四:修改布局文件:
layout/main.xml
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开新窗口 1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开新窗口 2"
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开新窗口 1"/&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开新窗口 2"/&
&/LinearLayout&
上面这样写并不好,因为我们直接将字符串 “打开新窗口 1” 和 “打开新窗口 2” 放在了布局文件里。
本来这好像没什么。但是上一篇文章里我已经写到了,android 提供了一种资源管理的机制,我们可以将 “打开新窗口 1” 和 “打开新窗口 2“ 这样的字符串资源交给系统来管理,编译环境会为这些资源生成一个唯一的 ID,编程人员只需要通过这个 ID,就能引用这个资源。
因此,这里最好的做法是,将 “打开新窗口 1” 和 “打开新窗口 2”
添加到 values/strings.xml 中,这个过程可以理解为 “向操作系统注册需要它管理的资源”,因为这里我们要注册的是字符串资源,因此,我们使用一个 &string& 标签来完成注册:
version="1.0" encoding="utf-8"
name="app_name"打开一个新窗口程序
name="button1"打开新窗口 1
name="button2"打开新窗口 2
&?xml version="1.0" encoding="utf-8"?&
&resources&
&string name="app_name"&打开一个新窗口程序&/string&
&string name="button1"&打开新窗口 1&/string&
&string name="button2"&打开新窗口 2&/string&
&/resources&
嗯,好啦!如果我是读者朋友们,我看到这篇文章,一定会骂人的!没有怀疑精神的程序员,不是优秀的程序员!
我们的怀疑是,这样做是做明显增加了开发者的负担。嗯,android 的框架设计师是否在一个月黑风高的晚上被驴踢过?
很幸运不是的。android 的设计者既然在开发者和资源间假设了一个隔离层,这个层肯定是要做事情的。
还是我前文所说,最了解操作系统的肯定是操作系统本身。操作系统不需要询问任何人,不需要编程者额外关注,就已经知道自己到底处在什么样的语言环境中,知道自己的分辨率大小,知道内存是否紧张等等。在本例中,我们可以在项目下新建一个目录,values-en,然后在这里面同样注册这样几个字符串:
version="1.0" encoding="utf-8"
name="app_name"Open new window
name="button1"open new 1
name="button2"open new 2
&?xml version="1.0" encoding="utf-8"?&
&resources&
&string name="app_name"&Open new window&/string&
&string name="button1"&open new 1&/string&
&string name="button2"&open new 2&/string&
&/resources&
用户在使用本程序之前,假死将语言环境调成 “英语” 环境,那么,显示在按钮上的文字就由“打开新窗口 1” 和 “打开新窗口 2” 变成了 “open new 1” 和 “open new 2” 。没有再比这更聪明的做法了。
注册的字符串,会在 R 文件中的 string 内部类里面生成静态常量,如:
public static final class string {
public static final int app_name=0x7f040000;
public static final int button1=0x7f040001;
public static final int button2=0x7f040002;
public static final class string {
public static final int app_name=0x7f040000;
public static final int button1=0x7f040001;
public static final int button2=0x7f040002;
按照上一篇中说的,我们如果要获取对应的字符串,表达式应该这样写:@string/button1 、 @string/button2。
于是修改 main.xml 内容为:
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"/&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"/&
&/LinearLayout&
五:界面效果如图:
六:如何响应按钮的点击行为?
在说出结论之前,我们想想在 html 中,我们是如何为一个按钮添加点击事件的?
是的,两种方式:
&input type="button" value="打开新窗口 1" onclick="add()" /&
当用户在浏览器中点击 “打开新窗口 1” 按钮时,就会调用 "add()" 这个 JS
函数,函数的签名可能是这样:
function add() {
&input type="button" value="打开新窗口 2"
id="btn_add"/&
一般的做法是在页面的加载时间里,动态为 id 为 btn_add 的按钮绑定事件处理:
window.onload=function(){
// 在页面加载的时候执行,也可以理解为,在页面 “创建” 时执行,与
Activity 的 onCreate 类似
btn_add = document.getElemenetById("btn_add");
// 首先从上下文获取目标控件。相当于在 Activity 里调用
findViewById。
btn_add.onclick = function() {
第一种的方式明显简单明了。第二种就稍显鸡飞狗跳了,有时候,光是 “从上下文获取目标控件” 就要写超过5行代码。
但是,我们看到的推荐的做法都是第二种,从设计上来讲,第二种做法利于开发人员的分工,减少了维护成本,使前台工程师更加专注,并使 JS 代码从标签中分离,实现表现和行为相分离 ... ...
我讨厌上纲上线。
android 中控件的事件处理机制也是类似的。
例如,我们可以为按钮直接写一个点击事件,此为方式一 :
&Button onClick="add" /&
在控件所在的 Activity 中,定义一个方法 ,方法必须接收一个唯一的参数:View -- 你不能再天马行空的自己传几个参数过去。
public void add(View view) {
public void add(View view) {
本例中,修改按钮一的配置为:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"
因此,main.xml 被绑定到了默认的启动窗口 -- MainActivity 上,因此需要在 MainActivity 中添加,openView(View view) 方法,此方法若不存在,或签名错误,应用程序将抛出异常,并强制结束。
添加了 openView 方法的 MainActivity 代码清单:
package wjh.android.
import android.app.A
import android.os.B
import android.view.V
import android.widget.B
import android.widget.T
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
public void openNew(View view) {
Button button = (Button)
String text = (String) button.getText();
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
package wjh.android.
import android.app.A
import android.os.B
import android.view.V
import android.widget.B
import android.widget.T
public class MainActivity extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
* 处理按钮一的点击事件
* @param view 触发本次事件的控件
public void openNew(View view) {
* 任何可显示的控件,都是 View 的子类。
* 我们确定触发此事件的就是一个 Button,因此可以强转。
Button button = (Button)
/* 获取到 Button 上显示的文本 */
String text = (String) button.getText();
* Toast 可以在窗体上显示一个提示框。
* 第三个个参数表示提示框在窗体上显示的时间长度。
* Toast.LENGTH_LONG : 显示较长的时间,该常量是一个值为 1 的 int 值,因此可以直接写为 1 。
* Toast.LENGTH_SHORT: 较短的,该常量是一个值为 0 的 int 值,因此此处可以直接写为 0 。
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
// 一个经常犯的错误是忘了调用 show 方法
重新部署 并运行程序,点击 “打开新窗口 1” 按钮后,效果如图所示:
这是第一种方式,另一种方式是在程序中获取要添加点击事件的按钮,再为其注册点击事件的监听对象:
首先第一个问题是程序中要如何获取到目标控件呢?回想上文所说的 html 中的处理方式:
&input type="button" value="打开新窗口 2"
id="addB"/&
程序员为这个 buttton 添加了一个 id ,这样能使我们在 JS 中十分方便的定位到此控件:getElementById
我很肯定的告诉各位,在 Activity 里面也有一个类型 JS 中根据控件 ID 获取控件的方法:findViewById
因此,当务之急是如何给 Button 添加一个 id 属性呢,借助 IDE ,我们找到了一个可能是我们需要的属性:“android:id”
可是,为这个属性赋值有点说道,它不能直接这样:android:id="button2"。因为 Android 的资源定位机制是基于 R
这个索引文件的,因此,若要在程序中直接访问到 Button,必须想办法将这个 id 属性添加到 R 文件中,并且使它指向 Button。
因此要用到一个重要的表达式:@+id/button2 。
因为前一篇中说道 @ 是代表 R 文件的,而 @+id 翻译过来就是:向 R 文件的 id 内部类新增... ... 。新增什么呢?就是 “/” 后的 button2。保存配置之后,再点击 R 文件查看,发现其内部多了一个 id 内部类,id 内部类里面有多了一个常量:button2。实际上,这个常量,就是指向我们配置处的 Button 的索引。因此,我们代码里就可以通过
findViewById(R.id.button2) 来获取到此控件。
因此首先我们为本例中的一个按钮添加一个 id 属性:
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
&!-- 按钮1 使用 android:onClick 绑定点击事件 --&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"/&
&!-- 按钮2 添加了android:id 属性 --&
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"/&
&/LinearLayout&
然后在 MainActivity 里,获取这个按钮,并为其注册监听对象 :
package wjh.android.
import android.app.A
import android.os.B
import android.view.V
import android.widget.B
import android.widget.T
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button button = (Button)
String text = (String) button.getText();
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
public void openNew(View view) {
Button button = (Button)
String text = (String) button.getText();
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
package wjh.android.
import android.app.A
import android.os.B
import android.view.V
import android.widget.B
import android.widget.T
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button2);
Button 注册点击事件监听对象,采用了匿名内部类的方式。 */
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button button = (Button)
String text = (String) button.getText();
/* MainActivity.this 因为要接收当前上下文对象,其实就是当前的 Activity。
* 因此在内部类里要访问外部类属性,采用
MainActivity.this 这种方式 */
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
* 处理按钮一的点击事件
* @param view 触发本次事件的控件
public void openNew(View view) {
* 任何可显示的控件,都是 View 的子类。
* 我们确定触发此事件的就是一个 Button,因此可以强转。
Button button = (Button)
/* 获取到 Button 上显示的文本 */
String text = (String) button.getText();
* Toast 可以在窗体上显示一个提示框。
* 第三个个参数表示提示框在窗体上显示的时间长度。
* Toast.LENGTH_LONG : 显示较长的时间,该常量是一个值为 1 的 int 值,因此可以直接写为 1 。
* Toast.LENGTH_SHORT: 较短的,该常量是一个值为 0 的 int 值,因此此处可以直接写为 0 。
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
// 一个经常犯的错误是忘了调用 show 方法
重新部署后,点击 “打开新窗口 2” 后的效果与按钮1类似,不再贴图。
七:解决如何响应按钮点击事件这个问题后,剩下的唯一问题就是如何打开新的窗口。
其实所谓新的窗口就是一个新的 Activity。不管那么多,先将这个 Activity 建好再说:
public class OtherActivity extends Activity
然后依照上一篇的说法,像在 struts 中要使用其提供的组件一样,需要在功能清单文件中注册或者说声明这个控件:
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="wjh.android.opennew"
android:versionCode="1"
android:versionName="1.0"&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".MainActivity"
android:label="@string/app_name"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&!-- 最新声明的 Activity --&
&activity android:name=".OtherActivity" /&
&/application&
&uses-sdk android:minSdkVersion="8" /&
&/manifest&
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="wjh.android.opennew"
android:versionCode="1"
android:versionName="1.0"&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".MainActivity"
android:label="@string/app_name"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&!-- 最新声明的 Activity --&
&activity android:name=".OtherActivity" /&
&/application&
&uses-sdk android:minSdkVersion="8" /&
&/manifest&
因为我将这个 Activity 新建在了应用所在包底下,即 manifest 标签的 package 属性指定的包下,所以才写成:
android:name=".OtherActivity",这种情况,前面的 "." 可以省略 ,若所建的类在其子包底下,则应写为 ".subpackage.OtherActiivty" 。若你实在纠结,或者你所建的 Activity 所在的类不与应用包名发生任何关系,例如,你的 Activity 在一个叫 “aa.bb.cc” 的包下也是可以的,这里就写类的完整名称就好 ,如:
&activity android:name="aa.bb.cc.OtherActivity" /&
这样是没有问题的。所以我认为 Android 这个属性名称取得不好(它有很多属性名都挺抽象、且够长),你说这个属性直接叫 class 或者叫 type 多好。一个创新意识太过兴盛且无条件予以鼓励的公司,做出来的东西就这些毛病。
回头看 MainActivity 是如何让显示出界面的呢?是因为这句代码:
setContentView(R.layout.main);
R.layout.main 指向了 layout /main.xml 界面文件,若我们将他改成 R.layout.other, 那么所显的界面自然就是 layout/other.xml 界面文件定义的界面内容了。因此,为了让 OtherActivity 显示出不同的内容,我们在 layout 文件夹下新建一个界面文件:选择 layout 文件夹,点击右键,选择弹出菜单的 New --& Android XML File
在出现的界面里的 File 栏键入文件的名字,other.xml。并且在下面一行文件类型栏选择 “Layout”,如图:
other.xml 的内容为:
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="你好。。。"
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout
xmlns:android="/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"&
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="你好。。。"/&
&!-- 这个字符串可以添加到 strings.xml 文件中,此处为了直观所以才直接这样写 --&
&/LinearLayout&
修改 OtherActivity 代码,参照 MainActivity,不难写出如下代码:
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
那么,如何激活这个 Activity 呢? 因为 Android 系统同一时间只允许一个 Activity 处于激活状态,因此只要这个 Actiivty 被激活了,那么原来的 Activity 自然就被拖出去 KO 了(实际上是暂停或停止 -- 大多数情况下,都不会被立即销毁)。
方式一 为:
Intent intent = new Intent(this, OtherActivity.class); //this 即当前 Activity
startActivity(intent);
于是我们在 “打开新窗口 1” 的 openNew 方法类修改其代码为:
public void openNew(View view) {
Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent);
* 处理按钮1的点击事件
* @param view 触发本次事件的控件
public void openNew(View view) {
Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent);
重新部署程序到模拟器,点击 “打开新窗口 1”:
点击后界面成功被切换,出现如图所示界面:
方式二:使用隐式意图。
简单的交代一下隐式意图的概念。
方式一使用的 Intent intent = new Intent(this, OtherActivity.class); 称之为显式意图,就是程序预先确切的知道 Intent 要达到的目标位置。
隐式意图处理想法的情况,就是,程序不确定(或者是故意形成这种不确定性,已使得程序可配)Intent 最终将对应到哪一个具体组件。
上一篇中我很详细的说到了这种设计理念。可以体会到 Android 的设计者,其对于 Android 的基本设计理念就是鼓励减少组件之间的耦合。
例如,本例中 Android 是如何让 MainActivity 成为主窗体的?有千千万万个程序要在这个平台运行,它不可能预测到,每个程序的主窗体是谁?于是他使用了隐式意图。规定,意欲设定为主窗体的 Activity 请设置意图的过滤模式为指定的模式,就是 action 为android.intent.action.MAIN,category 为 android.intent.category.LAUNCHER。我自然会在你程序启动的时候,嚣张的遍历你所有注册过的组件,然后去匹配这两个值,定位具体的 Activity 。
这是一个典型的、并且非常成功和优雅的的应用示例。
本例中,我们也可以体验一下这种激活 Activity 的方式:
1. 复制 OtherActivity 到 OtherActivity2。
然后需要注册这个 Activity,由于需要支持可以使用隐式意图来激活它,还需要定义 intent-filter:
android:name=".OtherActivity2"
android:name="wjh.android.action.otheractivity"
&!-- 隐式意图 Activity --&
&activity android:name=".OtherActivity2"&
&intent-filter&
&action android:name="wjh.android.action.otheractivity" /&
&/intent-filter&
&/activity&
简单起见,我们规定,只要一个 Intent 的 action 匹配了:wjh.android.action.otheractivity
就允许它使用我。因此,此处只定义了 action 的匹配模式。貌似是正确的,也确实,按常理,是无论如何也没有问题的。
于是,我们在 "打开新窗口 2" 的按钮点击事件里添加代码:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("wjh.android.action.otheractivity");
startActivity(intent);
Button 注册点击事件监听对象,采用了匿名内部类的方式。 */
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("wjh.android.action.otheractivity");
startActivity(intent);
好,运行。——报错:
(如何查看异常信息,Window -- Show View -- Other -- Android -- LogCat)
No Activity found to handle Intent { act=wjh.android.action.otheractivity }
说没有找到这样一个 Activity,可是我明明在声明
Activity 的时候,在意图过滤器里面定义了动作名称的啊,没写错吧。当时我是纠结了好一阵子。原来是这样的:
Android把所有传给 startActivity() 的隐式意图当作他们包含至少一个类别:"android.intent.category.DEFAULT"
也就是说,本例startActivity() 被推送的 Intent 除了将去匹配 action 为 wjh.android.action.otheractivity 这一个特征外,还将去匹配类别为:android.intent.category.DEFAULT,由于本例中,我们为 OtherActivity2 并没有设置类别(category) 的匹配,因此最终,startActivity() 开始的意图没有找到任何匹配项,将抛出异常,程序被迫中止。
既然知道这一点了,我们一定要铭记于心。于是修改 XML 配置为:
android:name=".OtherActivity2"
android:name="wjh.android.action.otheractivity"
android:name="android.intent.category.DEFAULT"
&!-- 隐式意图 Activity --&
&activity android:name=".OtherActivity2"&
&intent-filter&
&action android:name="wjh.android.action.otheractivity" /&
&category android:name="android.intent.category.DEFAULT" /&
&/intent-filter&
&/activity&
然后再部署应用,运行,点击 “打开新窗口 2” 按钮,程序正常运行。
八:到此为止。文章开头的需求已经全部完成。
最终的代码清单为:
AndroidManifest.xml
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
package="wjh.android.opennew"
android:versionCode="1"
android:versionName="1.0"
android:icon="@drawable/icon" android:label="@string/app_name"
android:name=".MainActivity"
android:label="@string/app_name"
android:name="android.intent.action.MAIN"
android:name="android.intent.category.LAUNCHER"
android:name=".OtherActivity"
android:name=".OtherActivity2"
android:name="wjh.android.action.otheractivity"
android:name="android.intent.category.DEFAULT"
android:minSdkVersion="8"
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="wjh.android.opennew"
android:versionCode="1"
android:versionName="1.0"&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".MainActivity"
android:label="@string/app_name"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&!-- 最新声明的 Activity --&
&activity android:name=".OtherActivity" /&
&!-- 隐式意图 Activity --&
&activity android:name=".OtherActivity2"&
&intent-filter&
&action android:name="wjh.android.action.otheractivity" /&
&category android:name="android.intent.category.DEFAULT" /&
&/intent-filter&
&/activity&
&/application&
&uses-sdk android:minSdkVersion="8" /&
&/manifest&
strings.xml
MainActivity.java
OtherActivity.java
OtherActivity2.java
九:顺便将 Activity 之间传递参数的方式也记录一下:
看了一下当时写的笔记,挺全的,因此直接复制笔记:
--------------------------------------------------------------------------------------------------------
7. 怎样给新的 Activity 传递参数
* 也需要通过意图来实现。因为意图本身就有 “携带数据” 的功能
* 因此只要将数据保存在意图中就可以了
可以调用 Intent 的 putXXXExtra 方法
Intent 提供了多种的重载后的 putExtra 方法。可以接收各种各样的单个参数
* Acticity 只需要调用 getExtras() 就可以获取到上一个 Acticity 传过来的参数集合
getExtras().get(String key) 可以获取具体参数的值
* 也可以很方便的通过 getXXXExtra方法来获取指定的单个参数值
如:getStringExtra、getIntExtra、getFloatExtra ...
示例代码:
MainActivity 传参并打开 OtherActicity
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("name", "wjh");
intent.putExtra("age", 21);
startActivity(intent);
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("name", "wjh");
intent.putExtra("age", 21);
startActivity(intent);
OtherActicity 读取参数并显示在 TextView 上
Intent intent = getIntent();
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0);
TextView textView =(TextView) findViewById(R.id.params);
textView.setText("name: " + name + ", age:" +age);
Intent intent = getIntent();
// 获取 Intent
String name = intent.getStringExtra("name"); // 获取 String 值
int age = intent.getIntExtra("age", 0); // 获取 int 值
TextView textView =(TextView) findViewById(R.id.params);
// 用于显示参数值的 TextView
textView.setText("name: " + name + ", age:" +age);
// 显示参数
8. 使用 Bundle 对象,批量给 Acticity 传递数据
MainActivity 传参
Bundle bundle = new Bundle();
bundle.putString("name", "wjh");
bundle.putInt("age", 21);
intent.putExtras(bundle);
Bundle bundle = new Bundle();
bundle.putString("name", "wjh");
bundle.putInt("age", 21);
// 将 Bundle 存放进 Intent
intent.putExtras(bundle);
OtherActicity 读取参数
Intent intent = getIntent();
String name = intent.getExtras().getString("name");
int age = intent.getExtras().getInt("age", 0);
Intent intent = getIntent();
String name = intent.getExtras().getString("name");
int age = intent.getExtras().getInt("age", 0);
9. Other Activity 返回数据
* 如果希望得到新被打开的 Acticity 的返回值。那么需要使用
startActivityForResult(Intent intent, int requestCode) 来激活打开 Acticity 的意图
* @param Intent : 要激活的意图
* @param requestCode : 用作标识此次请求, 区分其它请求(打开一个 Acticity 就类似于浏览器请求了一个新页面)
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
startActivityForResult(intent, 100);
10. 实验上一知识点
* 既然是得到新打开的 Acticity 的返回值。那么此 Acticity 应该已经被关闭。
* 如何关闭 Activity
调用 Activity 的 finish 方法
android.app.Activity.finish()
* 如何设置返回结果 (返回值)
Acticity 的 setResult 方法可以设置返回值
android.app.Activity.setResult(int resultCode, Intent data)
* @param resultCode 结果码, 用作标识此返回结果
* @param data 用意图做为返回参数的容器 (intent.putExtra)
android.app.Activity.setResult(int resultCode)
* @param resultCode 结果码, 用作标识此返回结果
* Main Acticity
如何获取返回数据
* 重写 Acticity 的 onActivityResult
* onActivityResult 会在 Activity 接收到参数的时候返回
public void
onActivityResult(int requestCode, int resultCode, Intent data)
* 代码示例:
MainActicity 打开 OtherActicity 并请求返回值。
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
startActivityForResult(intent, 100);
public void
onActivityResult(int requestCode, int resultCode, Intent data) {
Toast.makeText(this, data.getStringExtra("result"), 1).show();
super.onActivityResult(requestCode, resultCode, data);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
startActivityForResult(intent, 100);
* 处理 Activity 收到到请求数据结果
public void
onActivityResult(int requestCode, int resultCode, Intent data) {
// 用 Toast 打印返回结果
Toast.makeText(this, data.getStringExtra("result"), 1).show();
super.onActivityResult(requestCode, resultCode, data);
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity2 extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity2 extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
package wjh.android.
import wjh.android.opennew.R;
import wjh.android.opennew.R.
import android.app.A
import android.os.B
public class OtherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
package wjh.android.
import android.app.A
import android.content.I
import android.os.B
import android.view.V
import android.widget.B
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("wjh.android.action.otheractivity");
startActivity(intent);
public void openNew(View view) {
Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent);
package wjh.android.
import android.app.A
import android.content.I
import android.os.B
import android.view.V
import android.widget.B
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button2);
Button 注册点击事件监听对象,采用了匿名内部类的方式。 */
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("wjh.android.action.otheractivity");
startActivity(intent);
* 处理按钮1的点击事件
* @param view 触发本次事件的控件
public void openNew(View view) {
Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent);
version="1.0" encoding="utf-8"
xmlns:android="/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="你好。。。"
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout
xmlns:android="/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"&
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="你好。。。"/&
&!-- 这个字符串可以添加到 strings.xml 文件中,此处为了直观所以才直接这样写 --&
&/LinearLayout&
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
&!-- 按钮1 使用 android:onClick 绑定点击事件 --&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"/&
&!-- 按钮2 添加了android:id 属性 --&
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"/&
&/LinearLayout&
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
&!-- 按钮1 使用 android:onClick 绑定点击事件 --&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:onClick="openNew"/&
&!-- 按钮2 添加了android:id 属性 --&
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"/&
&/LinearLayout&
version="1.0" encoding="utf-8"
name="app_name"打开一个新窗口程序
name="button1"打开新窗口 1
name="button2"打开新窗口 2
&?xml version="1.0" encoding="utf-8"?&
&resources&
&string name="app_name"&打开一个新窗口程序&/string&
&string name="button1"&打开新窗口 1&/string&
&string name="button2"&打开新窗口 2&/string&
&/resources&
浏览 14914
浏览: 133312 次
来自: 广西
不错!学习一下。
发送这个publishers.jsp?page=*的时候会报错 ...
下了,好东东! 研究中
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 button按钮 的文章

 

随机推荐