【网学网提醒】:网学会员为广大网友收集整理了,Android开发指南-用户界面,希望对大家有所帮助!
Android开发指南用户界面开发指南-用户界面
菜单特性MenuFeatures
下面是适用于大多数菜单项的一些其他的特性。
菜单组Menugroups
当往菜单中添加新项时,你可以选择把它包含在一个组中。一个菜单组是一些可以共享某些特征的菜单项的集合,比如它们是否可见,是否可用,或者可否复选(checkable)。一个组由一个整数定义(或者一个XML里的资源ID)当我们使用接受一个groupId参数的add()。方法,比如add(int,
int,int,int)添加项时,它将被添加到组中。
你可以通过setGroupVisible()显示或隐藏菜单组;通过启用或禁用这个组;以及通过
setGroupCheckable()设置菜单项是否可以复选。可复选菜单项Checkablemenuitems
任何菜单项可以被用来表示选项开关的接口。这可以通过一个checkbox来指示一个单独的选项,或者通过一组单选按钮来表示互斥选项。(查看右边的截屏)。
注意:注意在图标菜单中的菜单项不能显示复选框或单选按钮。如果你选择让图标按钮中的菜单项变成可复选,那你必须在开关状态变化时自动通过切换图标和文本来指示这个状态。要让一个单独的项变成可复选,使用setCheckable()方法,如下:
menu.add(0,VIBRATE_SETTING_ID,0,"Vibrate").setCheckable(true);
这将为这个菜单项显示一个复选框(除非这是个图标菜单)。当这个item被选中时,通常
onOptionsItemSelected()会被调用。你应该在这里设置复选框状态。你可以用isChecked()来
查询这个菜单项的当前状态和用setChecked()来设置复选状态。就像
下面一样:
switch(item.getItemId()){caseVIBRATE_SETTING_ID:if(item.isChecked())item.setChecked(false);elseitem.setChecked(true);returntrue;...}
为了创建一组互斥的单选按钮,只要简单的为每个菜单项分配相同的groupID并调用
setGroupCheckable()。在这个例子里,你不需要为每个菜单项调用setCheckable()
方法,因为这个组被整体上设置为可复选。下面是在一个子菜单中创建两个互斥选项的例子:
SubMenusubMenu=menu.addSubMenu("Color");subMenu.add(COLOR_MENU_GROUP,COLOR_RED_ID,0,"Red");subMenu.add(COLOR_MENU_GROUP,COLOR_BLUE_ID,0,"Blue");subMenu.setGroupCheckable(COLOR_MENU_GROUP,true,true);
在setGroupCheckable()方法里,第一个参数是我们想设置为可复选的groupID。第二个参数表示是否设置为可复选。最后一个参数代表这些菜单项是否互斥(如果设置为false,则所有的菜单项将会是复选框而不是单选按钮。当这个组设置为互斥时(单选按钮),每当一个新的项被选中时,所有其它的项的选择会自动被清除。注意:注意可复选菜单项倾向于基于每次会话使用,而不保存到设备中。(例如,地图应用
程序 中的Mapmode设置并不会被保存-截屏如上)。如果有一些应用
程序设置你需要为用户保存它,那你应该使用首选项Preferences来保存数据,而通过一个PreferenceActivity来管理它们。
快捷键Shortcutkeys
可以为菜单项添加字母或数字快捷键,setAlphabeticShortcut(char)方法(设置字母快捷键),setNumericShortcut(int)方法(设置数字快捷键),或者setShortcut(char,int)(同时设置字母和数字)。非大小写敏感,比如:
menu.add(0,MENU_QUIT,0,"Quit").setAlphabeticShortcut('q');
现在,当菜单打开时(或者按住菜单键),按”q”键将选择该菜单项。这个快捷键将以菜单项的提示信息而显示在菜单项名称的下面(除了图标菜单项)。注意:注意快捷键不能添加进一个上下文菜单项中。
菜单项意图Menuitemintents
如果你已经阅读过应用程序基础ApplicationFundamentals,那么你应该多少知道一点Android意图。它允许程序互相绑定,分享信息,以及合作执行用户任务。就像你的应用程序可以发送一个意图来启动浏览器,邮件客户端或者另外一个活动一样,你可以从菜单中执行这样的动作。有两种途径来做这件事:定义一个意图然后分配给一个单独的菜单项,或者定义一个意图并允许Android查找设备上的活动然后动态的为每个符合意图标准的活动添加一个菜单项。请阅读意图和意图过滤器章节,以获取更多关于意图创建和应用
程序提供服务方面的信息。
为一个单独的菜单项设置一个意图Setanintentforasinglemenuitem
如果你想提供一个具体的菜单项来启动一个新的活动,那么你可以通过setIntent()方法具体地为这个菜单项定义一个意图。比如,onCreateOptionsMenu()方法里,在你可以用一个意图定义一个新菜单项如下:
MenuItemmenuItem=menu.add(0,PHOTO_PICKER_ID,0,"SelectPhoto");menuItem.setIntent(newIntent(this,PhotoPicker.class));
当这个菜单项被选中时,Android将自动启动这个活动。注意:注意这并不会给你的活动返回一个结果。如果你希望返回一个结果,那么不要使用setIntent()。相反,和通常情况一样在
onOptionsMenuItemSelected()oronContextMenuItemSelected()回调中处理并调用startActivityForResult().动态添加意图Dynamicallyaddintents
如果有潜在的多个活动和你的当前活动或所选择菜单项相关,那么这个应用
程序可以动态添加菜单项来执行其他的服务。在菜单创建过程中,定义一个意图,使用Intent.ALTERNATIVE_CATEGORY和/或Intent.SELECTED_ALTERNATIVE类别,当前选择(如果有的话)的MIME类型,以及其他需求,和你打开一个新活动时想要满足一个意图过滤器一样。然后调用
addIntentOptions()来让Android查找任何满
足那些需求的服务并为你添加它们到菜
单中。如果已安装的程序没有满足这个意图的,那么将不会有额外的菜单项被添加。注意:注意SELECTED_ALTERNATIVE是用来处理屏幕当前选中元素的。所以,它应该仅当在onCreateContextMenu()或onPrepareOptionsMenu()里面创建菜单项时使用,后者每次打开选项菜单时会被调用。下面是一个说明应用
程序如何
搜索附加服务来显示在它的菜单中的例子。
publicbooleanonCreateOptionsMenu(Menumenu){super.onCreateOptionsMenu(menu);//CreateanIntentthatdescribestherequirementstofulfill,tobeincluded
//inourmenu.TheofferingappmustincludeacategoryvalueofIntent.CATEGORY_ALTERNATIVE.Intentintent=newIntent(null,getIntent().getData());intent.addCategory(Intent.CATEGORY_ALTERNATIVE);//Searchfor,andpopulatethemenuwith,acceptableofferingapplications.menu.addIntentOptions(thisClass.INTENT_OPTIONS,//Menugroup0,//UniqueitemID(none)0,//Orderfortheitems(none)this.getComponentName(),//ThecurrentActivitynamenull,//Specificitemstoplacefirst(none)intent,//Intentcreatedabovethatdescribesourrequirements0,//Additionalflagstocontrolitems(none)null);//ArrayofMenuItemsthatcorrolatetospecificitems(none)returntrue;}
对于每个活动,如果其意图过滤器匹配我们所定义的那个意图,则将会添加一个菜单项,使用这个意图过滤器的android:label值作为菜单项的文本。这个addIntentOptions()方法也会返回所增加菜单项的数目。请同时注意,当addIntentOptions()被调用时,它将重写第一个参数指定的所有菜单组里的菜单项。如果想把你的活动的服务提供给其他应用
程序菜单,那么你只需要和通常情况一样定义一个意图过滤器。只是需要确保在一个意图过滤器的
元素的name属性中包含ALTERNATIVE和/或SELECTED_ALTERNATIVE值。比如:
......
在意图和意图过滤器文章中有更多关于创建意图过滤器的描述。要了解使用该技术的一个例子应用程序,可查看NotePad范例代码。
创建菜单CreatingMenus
菜单是任何应用程序的一个重要部分,提供了透露应用程序功能和设置的通用接口。Android为开发者提供了一个简单的编程接口来实现各种条件下的标准化应用程序菜单。Android提供了三种基础菜单类型:选项菜单OptionsMenu这是一个活动的主菜单。通过按下设备菜单键来显示它。选项菜单包含两组菜单项:
图标菜单IconMenu
这个是当用户按下菜单键时最初出现屏幕下方的item集合。它支持最多6个菜单项。只有这些菜
单支持图标而且这些菜单并不支持checkboxes或者radiobuttons。
扩展菜单ExpandedMenu
这是通过按“更多”菜单显现出来的一个竖向的项目列表。它仅当图标菜单过多时存在而且是由6个以及其它选项菜单组成。上下文菜单ContextMenu这是一个浮动菜单列表,通常在你长时间按在一个视图上时出现(比如一个列表项)子菜单Submenu这是一个浮动菜单列表,通过在选项菜单或上下文菜单选择菜单项显露出来。不支持嵌套子菜单。
选项菜单OptionsMenu
这个选项菜单通过按设备菜单键打开。打开后,出现图标菜单,可包含6个菜单项。如果添加多于6个菜单项,多出的部分将通过“更多”菜单项在扩展菜单中显示。扩展菜单项在多于6个菜单项时自动添加。选项菜单应该包含应用程序的基本功能以及任何必要的浏览项(例如,返回桌面或应用程序设置)。你还可以通过增加子菜单Submenus来组织主题和包含额外的菜单功能。当菜单第一次被打开时,系统会调用活动onCreateOptionsMenu()回调函数。重写该方法并生成传递给你的这个菜单对象。你可以通过扩充定义在XML文件中的一个菜单资源或者通过为你想要的每一个菜单项调用add()方法生成这个菜单。这个方法增加一个菜单项MenuItem,并返回新创建的对象。你可以用返回的MenuItem来设置附加属性如图标,快捷键,意图以及这个菜单项的其它设置。有多个add()方法。通常,你会使用接受一个itemId参数的那个。这是一个唯一的整数,允许你在回调函数中识别这个item。当一个菜单项从选项菜单中被选择时,你会接收到一个onOptionsItemSelected()回你可以通过请求itemId:getItemId()来识别它,调。这个回调传给你选中的MenuItem。这将返回add()方法分配的整数。一旦你识别了这个菜单项,就可以采取合适的动作。下面是一个活动里的例子,其中我们创建了一个选项菜单并处理菜单项的选择:
/*Createsthemenuitems*/publicbooleanonCreateOptionsMenu(Menumenu){menu.add(0,MENU_NEW_GAME,0,"NewGame");menu.add(0,MENU_QUIT,0,"Quit");returntrue;}/*Handlesitemselections*/publicbooleanonOptionsItemSelected(MenuItemitem){switch(item.getItemId()){caseMENU_NEW_GAME:newGame();returntrue;caseMENU_QUIT:quit();returntrue;}returnfalse;}
这个add()方法有四个参数:groupId,itemId,order,和title。groupId允许你关联这个菜单到一个菜单组中(更多参见下面的菜单组Menugroups)-这个例中,我们忽略掉它。itemId是用来识别菜单项的唯一的整数,在回调函数中使用。order允许我们定义菜单的显示顺序-缺省情况下,
它们以添加时的顺序排列。title当然是菜单的名
字(可以是一个字符串资源,为了本地化更加方便,建议你使用资源)。提示:提示如果你有一些可以以一个标题归类的菜单项,考虑以子菜单Submenu的方式组织它们。
增加图标Addingicons
图标也可以通过setIcon()函数被添加到菜单项中。
menu.add(0,MENU_QUIT,0,"Quit").setIcon(R.drawable.menu_quit_icon);
修改菜单Modifyingthemenu
如果有些时候你想在选项菜单被打开的时候re-write它,可以overrideonPrepareOptionsMenu()方法,该方法在每一次菜单被打开的时候调用。它将传递给你菜单对象,就像回调一样。这对于根据应用程序状态调整菜单选项很有用。注意:根据当前选择的item来这样做是一个不好的行为。记住,在触摸模式中,注意当改变菜单项时,将不会有一个选择或聚焦的item。相反,当你想基于UI中的某个特定item来提供功能时,你应该使用一个ContextMenu来完成这种行为。
上下文菜单ContextMenu
Android的上下文菜单在概念上和PC软件的右键菜单类似。当一个视图注册到一个上下文菜单时,执行一个在该对象上的“长按”(按住不动差不多两秒钟)动作,将出现一个提供相关功能的浮动菜单。上下文菜单可以被注册到任何视图对象中,不过,最常见的是用于列表视图ListView的item,在按中列表项时,会转换其背景色而提示将呈现上下文菜单。(电话联系人列表提供了关于这个特性的一个很好的例子)。注意:上下文菜单项不支持图标或快捷键。注意:上下文菜单项不支持图标或快捷键。为了创建一个上下文菜单,你必须重写这个活动的上下文菜单回调函数:
onCreateContextMenu()和onContextItemSelected()。在回调函数onCreateContextMenu()里,你可以通过使用一个add()方法来添加菜单项,或者通过扩
充一个定义在XML中的菜单资源。然后,通过registerForContextMenu()为这个视图注册一个上下文菜单ContextMenu.比如,下面的代码可以被用到Notepad应用程序中来为列表中的每一个注释添加一个上下文菜单:
publicvoidonCreateContextMenu(ContextMenumenu,Viewv,ContextMenuInfomenuInfo){super.onCreateContextMenu(menu,v,menuInfo);menu.add(0,EDIT_ID,0,"Edit");menu.add(0,DELETE_ID,0,"Delete");
}publicbooleanonContextItemSelected(MenuItemitem){AdapterContextMenuInfoinfo=(AdapterContextMenuInfo)item.getMenuInfo();switch(item.getItemId()){caseEDIT_ID:editNote(info.id);returntrue;caseDELETE_ID:deleteNote(info.id);returntrue;default:returnsuper.onContextItemSelected(item);}}
在onCreateContextMenu()中,除了给出将添加MenuItems的ContextMenu外,还需要给定选中的视图和一个上下文菜单信息ContextMenuInfo对象,该对象提供了选中对象的附加信
息。在本例中,onCreateContextMenu()没做什么特别的事-只是添加了一些菜单项。在
onContextItemSelected()回调函数中,我们从MenuItem中请求AdapterContextMenuInfo,
该对象提供当前选中项的信息。我们从中所要的只是这个选中项的列表ID,所以无论编辑还是这删除一个注释,我们通过这个对象的AdapterContextMenuInfo.info字段来找到该ID。个ID被传递给editNote()和deleteNote()方法来执行相应的动作。现在,要为一个列表视图中的所有项注册上下文菜单,我们可以传递整个的列表视图对象给
registerForContextMenu(View)方法:
registerForContextMenu(getListView());
记住,你可以传递任何视图对象来注册一个上下文菜单。这里,getListView()返回这个被用于Notepad应用程序的列表活动ListActivity中的列表视图对象。这样,这个列表中的任何item都被注册到这个上下文菜单。
子菜单Submenus
一个子菜单可以被添加进任何菜单中,但不能加入另外的子菜单中。当你的应用程序有很多功能可以按主题组织的时候,这将非常有用,就好比PC应用程序的菜单栏(文件,编辑,视图,。等)子菜单通过addSubMenu()加入到已有的菜单中而创建。该函数会返回一个子菜单SubMenu对象(菜单Menu的一个扩展)。然后你可以通过调用add()方法给这个菜单添加其他项,例如:
publicbooleanonCreateOptionsMenu(Menumenu){booleanresult=super.onCreateOptionsMenu(menu);
SubMenufileMenu=menu.addSubMenu("File");SubMenueditMenu=menu.addSubMenu("Edit");fileMenu.add("new");fileMenu.add("open");fileMenu.add("save");editMenu.add("undo");editMenu.add("redo");returnresult;}
子菜单中选择项的回调动作将由父菜单的回调方法处理。比如上面的例子,子菜单中的选择将由
onOptionsItemSelected()回调处理。
你也可以在XML中定义父菜单时增加子菜单。
在XML里定义菜单DefineMenusinXML
就像Android用户界面布局一样,你可以在XML文件中定义菜单,然后在你菜单的
onCreate...()回调函数中扩充它们。这使得你的应用程序代码简洁而且把更多的界面设计分
离到XML文件中,这更容易形象化。首先,在你的工程res/的目录下创建一个新的目录叫menu。你所有定义应用程序菜单的XML文件都应该放在这里。在一个菜单XML布局中,有三个合法的元素:
然后,在onCreateOptionsMenu()方法里,我们通过MenuInflater.inflate()方法扩充这个资源:
publicbooleanonCreateOptionsMenu(Menumenu){
MenuInflaterinflater=getMenuInflater();inflater.inflate(R.menu.options_menu,menu);returntrue;}
getMenuInflater()方法返回我们活动上下文的MenuInflater。然后我们调用inflate(),传递给它一个指向我们菜单资源的指针以及回调给出的菜单对象。
尽管和在onCreateOptionsMenu()创建菜单比较起来,上面的例子看起来做了更多的事情,但是如果处理更多的菜单项,这将省掉很多麻烦并让你的代码简洁。你可以通过把item元素打包进一个group中来定义菜单组menugroups,然后通过在一个
item中嵌入另外一个menu来创建子菜单。每个元素都支持必需的属性来控制快捷键,复选框,
图标,以及更多特性。要了解这些属性和更多的XML语法,请参见可用资源类型AvailableResourceTypes中的相关主题。
Android开发指南用户界面对话框开发指南-用户界面用户界面-对话框
创建对话框CreatingDialogs
收藏
对话框通常是一个显示在当前活动前面的小窗口。下面的活动失去焦点而由对话框接受所有的用户交互。对话框通常被用来当做通知或者运行中的应用程序相关的短暂活动。AndroidAPI支持下面的对话框对象类型:警告对话框AlertDialog这个对话框管理0,1,2,或3个按钮,和/或一个可包含复选框和单选按钮的可选项列表。这个警告对话框能够组建大多数用户界面而且是推荐使用的对话框类型。请查看下面的创建一个警告对话框CreatinganAlertDialog。进度对话框ProgressDialog用来显示一个进度轮或进度条。因此它是警告对话框的扩展,它也支持按钮。请查看下面的CreatingaProgressDialog。日期选择对话框DatePickerDialog一个允许用户选择日期的对话框。请查看HelloDatePicker指南。时间选择对话框TimePickerDialog一个允许用户选择时间的对话框。请查看HelloTimePicker指南.
如果你想定制你自己的对话框,你可以在基础对话框对象或任何上面列举的子类对话框上进行扩展并定义一个新的布局。请查看下面的创建自定义对话框CreatingaCustomDialog章节。
显示对话框ShowingaDialog对话框经常作为活动Activity的一部分来创建和显示。你通常应该从活动的onCreateDialog(int)回调方法里创建对话框。当你使用这个回调函数时,Android系统会有效的设置这个活动为每个对话框的所有者
,从而自动管理每个对话框的状态并挂靠到活动上。这样,每个对话框继承这个活动的特定属性。比如,当一个对话框打开时,菜单键显示为这个活动定义的选项菜单,音量键修改活动使用的音频流。注意:注意如果你决定在onCreateDialog()方法之外创建一个对话框,它将不会被附着到活动上。不过,你可以通过setOwnerActivity(Activity)把它附着到一个活动上。当你想要显示一个对话框时,调用showDialog(int)方法并传递一个唯一标识这个对话框的整数。当对话框第一次被请求时,Android从你的活动中调用onCreateDialog(int),你应该在这里初始化这个对话框Dialog。这个回调方法被传以和showDialog(int)相同的ID。当你创建这个对话框后,在方法的最后返回这个对象。在对话框被显示之前,Android还调用了可选的回调函数onPrepareDialog(int,Dialog).如果你想在每一次对话框被打开时改变它的任何属性,你可以定义这个方法。这个方法在每次打开对话框时被调用,而onCreateDialog(int)仅在对话框第一次打开时被调用。如果你不定义onPrepareDialog(),那么这个对话框将保持和上次打开时一样。这个方法也被传递以对话框的ID,和在onCreateDialog()中创建的对话框对象。定义onCreateDialog(int)和onPrepareDialog(int,Dialog)回调函数的最佳方法是使用一个switch语句来检查传递进来的id参数。每个case应该检查一个唯一的对话框ID然后创建和定义相应的对话框。比如,想象一下一个游戏使用两个不同的对话框:一个用来指示这个游戏已经暂停而另一个来指示游戏结束。首先,为每个对话框定义一个整数:staticfinalintDIALOG_PAUSED_ID=0;staticfinalintDIALOG_GAMEOVER_ID=1;然后,为每一个ID用一个switchcase定义这个onCreateDialog(int)回调函数:protectedDialogonCreateDialog(intid){Dialogdialog;switch(id){caseDIALOG_PAUSED_ID://dotheworktodefinethepauseDialogbreak;caseDIALOG_GAMEOVER_ID://dotheworktodefinethegameoverDialogbreak;default:dialog=null;}returndialog;
}注意:注意在这个例子里,case语句没有具体内容,因为这超出了本章讨论范围。当是时候显示其中之一的对话框时,使用对话框ID调用showDialog(int):showDialog(DIALOG_PAUSED_ID);
消除对话框DismissingaDialog当你准备关闭对话框时,你可以通过对这个对话框调用dismiss()来消除它。如果需要,你还可以从这个活动中调用dismissDialog(int)方法,这实际上将为你对这个对话框调用dismiss()方法.如果你想使用onCreateDialog(int)方法来管理你对话框的状态(就如同在前面的章节讨论的那样),然后每次你的对话框消除的时候,这个对话框对象的状态将
由该活动保留。如果你决定不再需要这个对象或者清除该状态是重要的,那么你应该调用removeDialog(int)。这将删除任何内部对象引用而且如果这个对话框正在显示,它将被消除。使用消除侦听器Usingdismisslisteners如果你希望你的应用程序在一个对话框消亡的时候执行一些流程,那么你应该附着一个on-dismiss侦听器到对话框上。首先定义DialogInterface.OnDismissListener接口。这个接口只有一个方法,onDismiss(DialogInterface),将在对话框消亡的时候被调用。然后简单的传递你的OnDismissListener实现给setOnDismissListener()。然而,请注意对话框也可以被“取消”。这是一个表明对话框被用户显示取消的特殊情况。这将在用户按“返回”按钮时发生,或者这个对话框显示的调用cancel()(也许通过对话框上的一个“取消”按钮)。当一个对话框被取消时,这个OnDismissListener依然会被通知到,但是如果你希望在对话框被显示取消时被通知到(而不是通常的消除方式),那么你应该通过DialogInterface.OnCancelListener。setOnCancelListener()注册一个
创建警告对话框CreatinganAlertDialog一个警告对话框是对话框的扩展类。它能够构建大多数对话框用户界面并且是推荐使用的对话框类型。你应该在具备如下特性的时候使用它:
????
一个标题一个文本消息1个,2个或3个按钮一个可选项列表(可选的复选框或单选按钮)
为了创建一个警告对话框,使用AlertDialog.Builder子类。通过AlertDialog.Builder(Context)获取一个构造器然后使用这个类的公共方法来定义警告对话框的所有属性。当得到构造器后,通过create().方法来获取警告对话框对象。下面的题目说明了如何使用AlertDialog.Builder类来定义不同的警告对话框属性。如果你在onCreateDialog()回调函数中使用下面的代码,你可以返回结果对话框对象来显示它。
增加按钮Addingbuttons为了创建一个如右图所示的包含并行按钮的警告对话框,使用set...Button()方法:AlertDialog.Builderbuilder=newAlertDialog.Builder(this);builder.setMessage("Areyousureyouwanttoexit?").setCancelable(false).setPositiveButton("Yes",newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intid){MyActivity.this.finish();}}).setNegativeButton("No",newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intid){dialog.cancel();}});AlertDialogalert=builder.create();首先,为这个对话框添加一个消息setMessage(CharSequence)。然后,开始函数链并设置该对话框为不能取消notcancelable(因此用户不能使用返回按钮关闭这个
对话框)对每个按钮,使用任一。set...Button()方法,比如setPositiveButton(),该方法接受按钮名称以及一个定义用户选中按钮后所采取动作的DialogInterface.OnClickListener。注意:注意你仅可以为这个警告对话框添加其中一种按钮类型。也就是,你不能包含多个“确定”按钮。这限制了可能的按钮数目只能是3个:确定,中立和否定。这些名字和你按钮的实际功能是技术上无关的,但是应该可以帮助你记录做了什么。增加一个列表Addingalist为了创建一个带有可选项列表的警告对话框,如右边所示,可使用setItems()方法:finalCharSequence[]items={"Red","Green","Blue"};
AlertDialog.Builderbuilder=newAlertDialog.Builder(this);builder.setTitle("Pickacolor");builder.setItems(items,newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intitem){Toast.makeText(getApplicationContext(),items[item],Toast.LENGTH_SHORT).show();}});AlertDialogalert=builder.create();首先,用setTitle(CharSequence)方法给对话框添加一个标题。然后,添加用setItems()添加一个可选项列表,该列表接受一组显示的items和一个DialogInterface.OnClickListener来定义用户选中按钮后所采取动作。增加复选框和单选按钮要在对话框里创建一个多选项列表(checkboxes)或者单选项(radiobuttons)可分别调用,
setMultiChoiceItems()和setSingleChoiceItems()方法。如果你在onCreateDialog()回调函数中创建这些可选列表,Android会帮你管理列表状态。只要这个活动是激活的,对话框会记住之前选中的items,但如果用户退出这个活动,用户选择将丢失。注意:为了在用户离开或暂停这个活动的时候能够保存选择,注意你必须通过活动生命期ActivityLifecycle来恰当的保存和恢复设置。为了永久保存选项,即使活动进程被完全终止,你需要使用数据存储DataStorage技术。要创建如右边所示的一个包含单选项列表的警告对话框,使用前面例子中相同的代码,不过需要把setItems()方法替换为setSingleChoiceItems()。finalCharSequence[]items={"Red","Green","Blue"};
AlertDialog.Builderbuilder=newAlertDialog.Builder(this);builder.setTitle("Pickacolor");builder.setSingleChoiceItems(items,-1,newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intitem){Toast.makeText(getApplicationContext(),items[item],Toast.LENGTH_SHORT).show();}});AlertDialogalert=builder.create();setSingleChoiceItems()的第二个参数是一个checkedItem整型数值,指示了基于0的缺省选择项的位置。“-1”代表不会有默认选择项。
创建进度对话框CreatingaProgressDialog进度对话框ProgressDialog是AlertDialog类
的一个扩展,可以为一个未定义进度的任务显示一个旋转轮形状的进度动画,或者为一个指定进度的任务显示一个进度条。这个对话框也能提供按钮,比如一个取消下载的按钮。可以简单的通过调用ProgressDialog.show()方法来显示一个进度对话框。比如,可以很简单的得到右边显示的进度对话框,而不必通过onCreateDialog(int)回调管理这个对话框,如下所示:ProgressDialogdialog=ProgressDialog.show(MyActivity.this,"","Loading.Pleasewait...",true);第一个参数是应用程序上下文Context,第二个是对话框标题(此处为空),第三个是信息,最后这个参数表明进度是否是不确定的(这只和创建进度条有关,下一章会有描述)。进度对话框的缺省类型是一个旋转轮,如果你想创建一个间隔进度,需要更多的代码,如下章所述。显示进度条Showingaprogressbar使用动画进度条显示进度:1.用类构造器初始化进度对话框,ProgressDialog(Context)。2.用setProgressStyle(int)方法设置进度风格为"STYLE_HORIZONTAL"以及设置其它属性,比如消息。3.当你准备显示这个对话框时,调用show()或者从onCreateDialog(int)回调中返回ProgressDialog。
4.你可以通过调用setProgress(int)设置当前进度百分比或者调用incrementProgressBy(int)方法增加进度值。比如,你的设置可能看起来像这样:ProgressDialogprogressDialog;progressDialog=newProgressDialog(mContext);progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);progressDialog.setMessage("Loading...");progressDialog.setCancelable(false);设置很简单。大多数创建代码也用来更新进度。你可能意识到创建另外一个线程来完成这个进度报告的工作是有必要的,进度通过一个对象返回给活动的用户界面线程。如果你对如何通过一个Handler使用另外的线程不熟悉,请参见下面的例子:ExampleProgressDialogwithasecondthread这个例子使用了另外一个线程来跟踪进程进度(计数到100)。这个线程在每次进度更新时通过一个句柄Handler发回一条消息Message。主活动然后更新进度对话框。packagecom.example.progressdialog;
importandroid.app.Activity;importandroid.app.Dialog;importandroid.app.ProgressDialog;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;
publicclassNotificationTestextendsActivity{staticfinalintPROGRESS_DIALOG=0;Buttonbutton;ProgressThreadprogressThread;ProgressDialogprogressDialog;
/**Calledwhentheactivityisfirstcreated.*/publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);
//Setupthebuttonthatstartstheprogressdi
alogbutton=(Button)findViewById(R.id.progressDialog);button.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){showDialog(PROGRESS_DIALOG);
}});}
protectedDialogonCreateDialog(intid){switch(id){casePROGRESS_DIALOG:progressDialog=newProgressDialog(NotificationTest.this);progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);progressDialog.setMessage("Loading...");progressThread=newProgressThread(handler);progressThread.start();returnprogressDialog;default:returnnull;}}
//DefinetheHandlerthatreceivesmessagesfromthethreadandupdatetheprogressfinalHandlerhandler=newHandler(){publicvoidhandleMessage(Messagemsg){inttotal=msg.getData().getInt("total");progressDialog.setProgress(total);if(total>=100){dismissDialog(PROGRESS_DIALOG);progressThread.setState(ProgressThread.STATE_DONE);}}};
/**Nestedclassthatperformsprogresscalculations(counting)*/privateclassProgressThreadextendsThread{HandlermHandler;finalstaticintSTATE_DONE=0;finalstaticintSTATE_RUNNING=1;intmState;inttotal;
ProgressThread(Handlerh){mHandler=h;}
publicvoidrun(){mState=STATE_RUNNING;
total=0;while(mState==STATE_RUNNING){try{Thread.sleep(100);}catch(InterruptedExceptione){Log.e("ERROR","ThreadInterrupted");}Messagemsg=mHandler.obtainMessage();Bundleb=newBundle();b.putInt("total",total);msg.setData(b);mHandler.sendMessage(msg);total++;}}
/*setsthecurrentstateforthethread,*usedtostopthethread*/publicvoidsetState(intstate){mState=state;}}}
创建自定义对话框CreatingaCustomDialog如果你想为对话框做一个自定义的设计,你可以为对话框窗口创建自己的布局和部件元素。当你定义好布局后,传递根视图对象或者布局资源ID给setContentView(View)方法。比如,创建如右图所示对话框:1.创建一个XML布局以custom_dialog.xml保存:
这个XML在一个LinearLayout里定义了一个ImageView和一个TextView.2.设置上面这个布局作为对话框的内容视图并为这个ImageView和TextView元素定义内容:
ContextmContext=getApplicationContext();Dialogdialog=newDialog(mContext);dialog.setContentView(R.layout.custom_dialog);dialog.setTitle("CustomDialog");TextViewtext=(TextView)dialog.findViewById(R.id.text);text.setText("Hello,thisisacustomdial
og!");ImageViewimage=(ImageView)dialog.findViewById(R.id.image);image.setImageResource(R.drawable.android);
实例化对话框后,用setContentView(int)设置你的自定义布局作为这个对话框的内容视图,以布局资源ID作为参数。现在这个对话框有一个已定义的布局,你可以用findViewById(int)方法从布局中抓取视图对象。3.就这样了。你现在可以显示该对话框了,参见ShowingADialog中的描述。以基类对话框创建的对话框必须有一个标题。如果你不调用setTitle(),那么标题占用的空间保持为空,但然仍然可见。如果你根本不想要一个标题,那你应该使用警告对话框AlertDialog来创建你的自定义对话框。而,因为警告对话框可以很简单的通过AlertDialog.Builder类来创建,你并不需要访问上面使用的setContentView(int)方法。相反,你必须使用setView(View)。这个方法接受一个视图View对象,所以你需要在XML中扩充布局的根视图。要扩充XML布局,用getLayoutInflater()或getSystemService()方法获取LayoutInflater,然后调用inflate(int,ViewGroup),这里第一个参数是布局资源ID而第二个参数是根视图的ID。在此处,你可以使用扩充布局来查找视图对象和为ImageView和TextView元素定义内容。然后实例化AlertDialog.Builder并调用setView(View)为该对话框设置扩充布局。下面是一个例子,在一个警告对话框中创建自定义布局:AlertDialog.Builderbuilder;AlertDialogalertDialog;
ContextmContext=getApplicationContext();LayoutInflaterinflater=(LayoutInflater)mContext.getSystemService(LAYOUT_INFLATER);Viewlayout=inflater.inflate(R.layout.custom_dialog,(ViewGroup)findViewById(R.id.layout_root));
TextViewtext=(TextView)layout.findViewById(R.id.text);text.setText("Hello,thisisacustomdialog!");
ImageViewimage=(ImageView)layout.findViewById(R.id.image);image.setImageResource(R.drawable.android);
builder=newAlertDialog.Builder(mContext);builder.setView(layout);alertDialog=builder.create();在你的自定义布局中使用警告对话框可以让你利用警告对话框的内置特性比如管理按钮,可选列表,一个标题,一个图标等。想获取更多信息,请参考Dialog和AlertDialog.Builder类的相关文档。
Android开发指南用户界面事件处理开发指南-用户界面用户界面-事件处理
处理用户界面事件HandlingUIEvents
收藏
在Android上,不止一个途径来侦听用户和应用程序之间交互的事件。对于用户界面里的事件,侦听方法就是从与用户交互的特定视图对象截获这些事件。视图类提供了相应的手段。在各种用来组建布局的视图类里面,你可能会注意到一些公共的回调方法看起来对用户界面事件有用。这些方法
在该对象的相关动作发生时被Android框架调用。比如,当一个视图(如一个按钮)被触摸时,该对象上的onTouchEvent()方法会被调用。不过,为了侦听这个事件,你必须扩展这个类并重写该方法。很明显,扩展每个你想使用的视图对象(只是处理一个事件)是荒唐的。这就是为什么视图类也包含了一个嵌套接口的集合,这些接口含有实现起来简单得多的回调函数。这些接口叫做事件侦听器eventlisteners,是用来截获用户和你的界面交互动作的“门票”。当你更为普遍的使用事件侦听器来侦听用户动作时,总有那么一次你可能得为了创建一个自定义组件而扩展一个视图类。也许你想扩展按钮Button类来使某些事更花哨。在这种情况下,你将能够使事件处理器eventhandlers类来为你的类定义缺省事件行为。
事件侦听器EventListeners
事件侦听器是视图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。当正在创建一个上下文菜单的时候被调用(作为持续的“长点击”动作的结果)。参阅创建菜单CreatingMenus章节以获取更多信息。这些方法是它们相应接口的唯一“住户”。要定义这些方法并处理你的事件,在你的活动中实现这个嵌套接口或定义它为一个匿名类。然后,传递你的实现的一个实例给各自的
View.set...Listener()方法。(比如,调用setOnClickListener()并传递给它你的OnClickListener
实现。)下面的例子说明了如何为一个按钮注册一个点击侦听器:
//CreateananonymousimplementationofOnClickListenerprivateOnClickListenermCorkyListener=newOnClickListener(){publi
cvoidonClick(Viewv){//dosomethingwhenthebuttonisclicked}};protectedvoidonCreate(BundlesavedValues){...//CaptureourbuttonfromlayoutButtonbutton=(Button)findViewById(R.id.corky);//RegistertheonClicklistenerwiththeimplementationabovebutton.setOnClickListener(mCorkyListener);...}
你可能会发现把OnClickListener作为活动的一部分来实现会便利的多。这将避免额外的类加载和对象分配。比如:
publicclassExampleActivityextendsActivityimplementsOnClickListener{protectedvoidonCreate(BundlesavedValues){...Buttonbutton=(Button)findViewById(R.id.corky);button.setOnClickListener(this);}//ImplementtheOnClickListenercallbackpublicvoidonClick(Viewv){
//dosomethingwhenthebuttonisclicked}...}
注意上面例子中的onClick()回调没有返回值,但是一些其它事件侦听器必须返回一个布尔值。原因和事件相关。对于其中一些,原因如下:?onLongClick()–返回一个布尔值来指示你是否已经消费了这个事件而不应该再进一步处理它。也就是说,返回true表示你已经处理了这个事件而且到此为止;返回false表示你还没有处理它和/或这个事件应该继续交给其他on-click侦听器。?onKey()–返回一个布尔值来指示你是否已经消费了这个事件而不应该再进一步处理它。也就是说,返回true表示你已经处理了这个事件而且到此为止;返回false表示你还没有处理它和/或这个事件应该继续交给其他on-key侦听器。?onTouch()-返回一个布尔值来指示你的侦听器是否已经消费了这个事件。重要的是这个事件可以有多个彼此跟随的动作。因此,如果当接收到向下动作事件时你返回false,那表明你还没有消费这个事件而且对后续动作也不感兴趣。那么,你将不会被该事件中的其他动作调用,比如手势或最后出现向上动作事件。记住按键事件总是递交给当前焦点所在的视图。它们从视图层次的顶层开始被分发,然后依次向下,直到到达恰当的目标。如果你的视图(或者一个子视图)当前拥有焦点,那么你可以看到事件经由dispatchKeyEvent()方法分发。除了从你的视图截获按键事件,还有一个可选方案,你还可以在你的活动中使用onKeyDown()andonKeyUp()来接收所有的事件。注意:注意Android将首先调用事件处理器,其次是类定义中合适的缺省处理器。这样,从这些事情侦听器中返回true将停止事件向其它事件侦听器传播并且也会阻塞视图中的缺事件处理器的回调函数。因此当你返回true时确认你希望终止这个事件。
事件处理器EventHandlers
如果你从视图创建一个自定义组件,那么你将能够定义一些回调方法被用作缺省的事件处理器。在创建自定义组件Bu
ildingCustomComponents的文档中,你将学习到一些用作事件处理的通用回调函数,包括:?????
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)来捕获触
摸事件。
触摸模式TouchMode
当用户使用方向键或跟踪球浏览用户界面时,有必要给用户可操作的item(比如按钮)设置焦点,这样用户可以知道哪个item将接受输入。不过,如果这个设备有触摸功能,而且用户通过触摸来和界面交互,那么就没必要高亮items,或者设定焦点到一个特定的视图。这样,就有一个交互模式叫“触摸模式”。对于一个具备触摸功能的设备,一旦用户触摸屏幕,设备将进入触摸模式。自此以后,只有isFocusableInTouchMode()为真的视图才可以被聚焦,比如文本编辑部件。其他可触摸视图,如按钮,在被触摸时将不会接受焦点;它们将只是在被按下时简单的触发on-click侦听器。任何时候用户按下方向键或滚动跟踪球,这个设备将退出触摸模式,然后找一个视图来接受焦点,用户也许不会通过触摸屏幕的方式来恢复界面交互。触摸模式状态的维护贯穿整个系统(所有窗口和活动)。为了查询当前状态,你可以调用isInTouchMode()来查看这个设备当前是否处于触摸模式中。
处理焦点HandlingFocus
框架将根据用户输入处理常规的焦点移动。这包含当视图删除或隐藏,或者新视图出现时改变焦点。视图通过isFocusable()方法表明它们想获取焦点的意愿。要改变视图是否可以接受焦点,可以调用setFocusable()。在触摸模式中,你可以通过isFocusableInTouchMode()查询一个视图是否允许接受焦点。你可以通过setFocusableInTouchMode()方法来改变它。焦点移动基于一个在给定方向查找最近邻居的算法。少有的情况是,缺省算法可能和开发者的意愿行为不匹
配。在这些情况下,你可以通过下面布局文件中的XML属性提供显式的重写:nextFocusDown,nextFocusLeft,nextFocusRight,和nextFocusUp。为失去焦点的视图增加这些属性之一。定义属性值为拥有焦点的视图的ID。比如:
通常,在这个竖向布局中,从第一个按钮向上浏览或者从第二个按钮向下都不会移动到其它地方。现在这个顶部按钮已经定义了底部按钮为nextFocusUp(反之亦然),浏览焦点将从上到下和从下到上循环移动。如果你希望在用户界面中声明一个可聚焦的视图(通常不是这样),可以在你的布局定义中,为这个视图增加android:focusableXML属性。把它的值设置成true。你还可以通过
android:focusableInTouchMode在触摸模式下声明一个视图为可聚焦。想请求一个接受焦点的特定视图,调用requestFocus()。要侦听焦点事件(当一个视图获得或者失去焦点时被通知到),使用onFocusChange(),如上面
事件侦听器EventListeners一章所描述的那样。
Android开发指南用户界面用户通知开发指南-用户界面用户界面-用户通知
通知用户NotifyingtheUser
收藏
某些情况下需要通知用户你的应用程序中发生了一个事件。一些事件请求用户应答而另外一些则不需要。比如:
???
当一个事件比如保存文件结束时,应该出现一条消息确认保存成功。如果一个后台运行的应用程序需要用户关注,这个应用程序应该创建一个通知来允许用户在方便时进行应答。如果这个应用程序在执行一个用户必须等待的任务(比如家在一个文件),那么应用程序应该显示一个盘旋的进度轮或进度条。
所有这些通知任务可以通过一个不同的技术获取到:
???
一个消息条通知ToastNotification,用于从后台出现的简短信息。forbriefmessagesthatcomefromthebackground.一个状态条通知AStatusBarNotification,用于来自后台的持续提醒并请求用户应答。一个对话框通知ADialogNotification,用于活动相关的通知。
这篇文档总结了用来通知用户的所有这些技术并包含相应的链接。
消息条通知ToastNotification
一个消息条通知是一个在窗口表面弹出的信息。它只填充内容所需的空间并且用户当前活动仍然保持可见和可交互。这个通知自动渐入渐出,而且不接受交互事件。因为消息条可以从一个后台服务Service中创建,即便应用程序不可见,它也将呈现出来。一个消息条是用来显示简短文本信息的
最好方法,比如“文件已保存”,当你很确信用户正在关注屏幕时。一个消息条不能接受用户交互事件;如果你希望用户应答并采取相应动作,请考虑使用一个状态条通知StatusBarNotification。更多信息,请参考创建消息条通知CreatingToastNotifications.
状态条通知StatusBarNotification
一个状态条通知添加一个图标到系统状态栏上(以及一个可选的滚动条文本信息)以及在这个“通知”窗口中的一个扩展消息。当用户选择这个扩展消息时,Android发出这个通知所定义的一个意图(通常是启动一个活动)。你也可以配置这个通知来通过一个声音,震动和设备上的闪烁灯来警告用户。当你的应用程序以后台服务运行并需要通知用户事件时,这类通知是一个理想的方式。如果你需要在活动仍处于焦点下时警告用户一个发生的事件,请考虑使用对话框通知DialogNotification。更多信息,请参考创建状态条通知CreatingStatusBarNotifications。
对话框通知DialogNotification
一个对话框通常是出现在当前活动前面的一个小窗口。背后的活动丢失焦点而由这个对话框接受所有的用户交互。对话框通常用做和运行中应用程序直接相关的通知和短暂活动。你应该使用对话框来显示一个进度条或者一个需要用户确认的短消息(比如带有“确认”和“取消”按钮的一个警告)。你也可以把对话框作为构成应用程序界面整体的组件以及用于除了通知之外的其它目的。要完整讨论所有可用对话框资源,包括用作通知,请参考创建对话框CreatingDialogs。
Android开发指南用户界面通用布局对象开发指南-用户界面用户界面-通用布局对象
收藏
通用布局对象CommonLayoutObjects
本章描述了可用于你的应用程序的一些更为通用的布局对象类型。像所有的布局一样,它们是ViewGroup.的子类。也可以参见HelloViews教程,有更多关于使用Android视图布局的指南。
框架布局FrameLayout
框架布局FrameLayout是最简单的布局对象类型。它基本上是一个屏幕上的空白空间,你可以稍后填充一个对象-比如,一个切入切出的图片。所有框架布局的子元素被钉在屏幕左上角;你不能为子视图指定一个不一样的位置。后续的子视图只是简单在之前的视图上方绘制,部分或完全的掩盖它们(除非这个新的对象是透明的)。
线性布局LinearLayout
线性布局LinearLayout在单一方向上对齐所有的子视图-竖向或者横向,这依赖于你怎么定义方向orientation属性。所有子视图依次堆积,所以一个竖向列表每行只有一个子视图,不管它们有多宽,而一个横向列表将只有一行高(最高子视图的高度,加上填充
)。一个线性布局LinearLayout会考虑子视图之间的边缘空白margins以及每个子视图的引力属性(靠右,居中,或者靠左)。线性布局LinearLayout也支持给每个单独的子视图分配一个权重。这个属性分配一个“重要性”数值给一个视图,并允许它扩展来填充父视图的任何剩余空间。子视图可以指定一个整型权重值,然后任何这个视图组中的剩余空间将按照子视图声明的比重来分配给它们。缺省权重是0。比如,如果有三个文本框,其中两个声明权重为1,而另一个未给定数值(0),这第三个没有权重的文本框将不会增长而只是占据其内容所要求的空间。其它两个将均匀分配剩余的空间。如果把第三个控件权重改为2,那意味着它被声明为比其它两个“更为重要”,因此它将占据整个空间的一半,而前面两个均分剩下的空间。
提示:要在屏幕上创建一个均衡尺寸的布局,可创建一个容器视图组对象,其layout_width和提示
layout_height属性设置为fill_parent;把子视图的height或width赋值为0;然后根据比例为每个子视图分配相关的weight值。
下面的两个窗体呈现了一个带有若干元素的线性布局LinearLayout:一个按钮,一些标签和文本框。这些文本框把它们的宽度设置为填充父视图(fill_parent);其他元素设置为包含内容。这两个窗体的区别是左边的那个没有设置权重,(wrap_content)引力属性为缺省的靠左对齐。而右边那个窗体中,评论文本框权重被设置为1。如果名字也设置成1,那么名字和评论将一样高。
在一个水平方向的线性布局LinearLayout中,items按照文本底线位置来对齐(第一个元素的第一行-最上边或最左边-被当作参考行)。这样用户在窗体中浏览元素时并不需要上下跳动来阅读相邻元素中的文本。这个特性可以通过在XML布局中设置
android:baselineAligned="false"来关闭。
要查看其他示例代码,参见HelloLinearLayout教程。
表布局TableLayout
表布局TableLayout把它的子视图定位到行和列中。表布局容器不显示行,列和单元的边界线。表的列和最多行单元数一样多。一个表可以有空单元,但是单元不能像HTML里面那样跨列。TableRow对象是一个TableLayout的子视图(每个TableRow定义了表中的一个单独行)每行。有0或多个单元,可用任何其他视图定义。因此,行单元可能由各个视图对象组成,ImageView如或TextView对象。一个单元也可以是一个ViewGroup对象(比如,你可以嵌入另一个表布局作为一个单元)。下面的示例布局有两行,各有两个单元。旁边的截图显示了效果,单元边界被显示为虚线
(为了增加视觉效果)。
android:text="@string/table_layout_4_save"android:padding="3dip"/>
列可以被隐藏,带有延伸标记并填充可用屏幕空间,或者可以被标记为可收缩来强制这个列缩小直到表适合屏幕。参见TableLayoutreference文档获取更多信息。示范代码,参见HelloTableLayout教程。
相对布局RelativeLayout
相对布局RelativeLayout允许子视图指定它们和父视图或彼此之间的相对位置(通过ID指定)。因此你可以按正确的顺序对齐两个元素,或者让一个视图在另外一个下面,居于屏幕中间,左边的中间,等等。元素通过给定顺序来绘制,因此如果这第一个元素在屏幕中间,其他以它对齐的元素都会对齐到屏幕中间。同样,因为这个顺序,如果使用XML来指定这个布局,你将引用的元素(为了定位其它视图对象)必须被列在XML文件中,在你通过引用ID从其他视图中引用它之前。这个下面的例子显示了一个XML文件及其界面效果。注意,在属性中引用相对元素(比如,layout_toLeft)时使用了一个相对资源语法来引用ID(@id/id)。
其中一些特性直接由元素支持,另外一些由它的LayoutParams成员变量支持(为所有这个屏幕中的元素子类化RelativeLayout,因为所有元
素都是RelativeLayout父对象的子元素)。已定义的相对布局RelativeLayout参数是:
width,height,below,alignTop,toLeft,padding[Bottom|Left|Right|Top],注意其中一些参数明确支持相对布局位置-它们以及margin[Bottom|Left|Right|Top]。
的数值必须是你的相对位置元素的ID。比如,为一个TextView分配参数
toLeft="my_button"将把TextView放在视图ID为my_button的左边(这必须写在XML
中的TextView前面)。示范代码,参见HelloRelativeLayout教程。
关于重要视图组的总结SummaryofImportantViewGroups
下面这些对象都用来容纳用户界面元素。一些提供了自己的可见界面格式,而其他一些是不可见的结构,仅仅用来管理子视图的布局。类描述
框
架
布
局
作为一个视图框架来显示一个单独的对象。
FrameLayout
画廊Gallery
一个水平滚动的图像显示。
网
格
视
图
显示一个滚动网格m列n行。
GridView
线
性
布
局
一个把子视图组织进单个水平或竖向行的布局。它创建一个滚动条如果窗口长度超过屏幕长度的话。
LinearLayout
列表视图ListView
显示一个滚动单列列表。
相
对
布
局
使你可以指定子对象之间的相对位置(如,A在B的左边)或者相对于父对象的位置(如,与父视图顶部对齐)
RelativeLayout
滚
动
视
图
一个竖向的滚动元素列。
ScrollView
微调器Spinner
从一组数据中每次显示一个单独的项,在一个单行的文本框里。很像可以横向或竖向滚动的单行列表框。(译注:这个并不是windows平台通常理解的那个用来上下调整数值的小控件SpinControl,虽然名字很相近)
平
面
视
图
提供一个专门的绘画平面的直接访问。它可以含有子视图层叠在这个平面上,但通常是为了给需要直接画像素的应用程序使用,而不是直接使用部件。
SurfaceView
标签栏TabHost
提供一个标签选择列表,监控用户点击动作并使得应用程序在一个标签被点击时改变屏幕显示。
表
布
局
一个表布局含有任意数量的行和列,每个单元包含你选择的部件。行的尺寸会自动调整来适应最大的列。单元边界不可见。
TableLayout
翻
转
视
图
一个一次只显示一项的列表,在一个单行文本框里。它可以被设置成定期切换items,就像幻灯片那样。
ViewFlipper
切
换
视
图
和翻转视图一样。
ViewSwitcher
Android开发指南用户界面绑定数据开发指南-用户界面用户界面-绑定数据
收藏
用AdapterView绑定数据BindingtoDatawithAdapterView
AdapterView是ViewGroup的子类,其子视图由绑定某类型数据的适配器Adapter决定。AdapterView用于当你需要在布局中显示存储数据时(不
是字符串或可绘制资源)。画廊Gallery,列表视图ListView,和微调控件Spinner就是适配器视图AdapterView子类的例子,用来绑定到特定类型的数据并以一定的方式显示。AdapterView对象有两个主要责任:??用数据填充布局处理用户的选择
用数据填充布局FillingtheLayoutwithData
通常是通过绑定AdapterView类到一个适配器Adapter来插入数据到布局中,这从外部获取数
据(可能是代码中所提供的一个列表数据,或者是设备数据库中的查询结果)。下面的代码示例执行以下操作:1.用现有的一个视图创建一个微调控件Spinner并将其绑定到一个新的ArrayAdapter,该适配器从本地资源中读取颜色数组。2.从一个视图创建另外的微调对象,并将其绑定到一个新的SimpleCursorAdapter,将从设。备联系人中读取人名(见Contacts.People)
//GetaSpinnerandbindittoanArrayAdapterthat//referencesaStringarray.Spinners1=(Spinner)findViewById(R.id.spinner1);ArrayAdapteradapter=ArrayAdapter.createFromResource(this,R.array.colors,android.R.layout.simple_spinner_item);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);s1.setAdapter(adapter);//LoadaSpinnerandbindittoadataquery.privatestaticString[]PROJECTION=newString[]{People._ID,People.NAME};Spinners2=(Spinner)findViewById(R.id.spinner2);Cursorcur=managedQuery(People.CONTENT_URI,PROJECTION,null,null);SimpleCursorAdapteradapter2=newSimpleCursorAdapter(this,android.R.layout.simple_spinner_item,//Useatemplate//thatdisplaysa//textviewcur,//GivethecursortothelistadatpernewString[]{People.NAME},//MaptheNAMEcolumninthe//peopledatabaseto...newint[]{android.R.id.text1});//The"text1"viewdefinedin//theXMLtemplateadapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);s2.setAdapter(adapter2);
注意Projection中的People._ID列是必须的,否则你将收到一个异常。如果,在你的应用程序生命周期过程中,你改变了适配器所读取的下层数据,你应该调用notifyDataSetChanged()方法。这将通知附着视图数据已经更改,它需要刷新自己。
处理用户的选择HandlingUserSelections
你通过设置类的AdapterView.OnItemClickListener成员变量为一个侦听器来处理用户的选择并且捕获选择变化。
//Createamessagehandlingobjectasananonymousclass.privateOnItemClickListenermMessageClickedHandler=newOnItemClickListener(){publicvoidonItemClick(AdapterViewparent,Viewv,intposition,longid){//Displayamessagebox.Toast.makeText(mContext,"You'vegotanevent",Toast.LENGTH_SHORT).show();}};//NowhookintoourobjectandsetitsonItemClickListenermember//toourclasshandlerobject.mHistoryView=(ListView)findViewById(R.id.his
tory);mHistoryView.setOnItemClickListener(mMessageClickedHandler);
Android开发指南用户界面绘制视图开发指南-用户界面用户界面-绘制视图
收藏
Android怎么绘画视图HowAndroidDrawsViews
当一个活动接收到焦点时,它将被要求绘制它的布局。Android框架将处理这个绘画的过程,但是活动必须提供它的布局层次的根节点。绘画从布局的根节点开始。它被要求来测量和绘制布局树。绘画通过遍历布局树并渲染每个和失效区域相交的视图来处理。相应的,每个视图组负责请求绘制它的子视图(通过draw()方法)而每个视图负责画它自己。因为这个树是顺序遍历的,这意味着先画父节点(也就是在屏幕后面),然后按照树中出现的顺序画其同层次节点。
框架将不会画不在失效区域的视图,而且还将会帮你画视图背景。你可以强制一个视图被重画,通过调用invalidate()。
绘画布局共有两步:一个度量过程和一个布局过程。度量过程在measure(int,int)里实现且是一个自顶向下的视图树遍历。每个视图在递归时往下推送尺寸规格。在度量过程的最后,每个视图都已经保存了自己的度量。第二个过程发生在layout(int,int,int,int)中并且也是自顶向下。在这个过程中,每个父节点负责定位它的所有子节点,通过使用在度量过程中计算得到的尺寸。
当一个视图的
measure()方法返回时,它的getMeasuredWidth()和getMeasuredHeight()值必须被设置,以及所有这个视图子节点的值。一个视图的度量的
宽度和高度值必须符合父视图引入的限制。这确保在度量过程之后,所有父节点接受所有它们的子节点的度量值。一个父视图可能会在其子视图上多次调用measure()方法。比如,父视图可能会通过未指定的尺寸调用measure来发现它们的大小,然后使用实际数值再次调用
measure(),如果所有子视图未做限制的尺寸总合过大或过小(也即是,如果子视图之间不能
对各自占据的空间达成共识的话,父视图将会干预并设置第二个过程的规则)。
要开始一个布局,可调用requestLayout()。这个方法通常在视图认为它自己不再适合它当前的边界的情况下被调用。
度量过程使用两个类来交流尺寸。View.MeasureSpec类被视图用来告诉它们的父视图它们想如何被度量和定位。基础的LayoutParams类仅仅描述了视图想有多大(高和宽)对于每个维度,。它可以指定下面之一:???一个准确的数值FILL_PARENT,这意味着视图想和父视图一样大(减掉填充padding)。WRAP_CONTENT,这意味着视图只想有刚好包装其内容那么大(加上填充)
对于不同的ViewGroup子类,有
相应的LayoutParams子类。比如,相对布局RelativeLayout有它自己的LayoutParams子类,这包含了能够让子视图横向和竖向居中显示的能力。度量规格(MeasureSpecs)被用来沿着树从父到子的下传度量需求。一个MeasureSpecs可以是下面三种模式之一:?UNSPECIFIED:这被父视图用来决定其子视图期望的尺寸。比如,一个线性布局可能在它的子视图上调用measure()onitschild,通过设置其高度为UNSPECIFIED以及一个宽度为EXACTLY240,来找出这个子视图在给定240像素宽度的情况下需要显示多高。??EXACTLY:这被父视图用来给子视图强加一个准确的尺寸。子视图必须使用这个大小,并确保其所有的后代将适合这个尺寸。AT_MOST:这被父视图用来给子视图强加一个最大尺寸。子视图必须确保它自己以及所有的后代都适合这个尺寸。