Using lists in Android [带翻译]
2015-02-08 13:27
399 查看
UsinglistsinAndroid(ListView)–Tutorial
原文地址:拉尔斯·沃格尔
Version4.6Copyright©2010,2011,2012,2013,2014vogellaGmbh2014年11月20日Android中ListView、ListActivity和ListFragment的使用本教程介绍了如何结合Activitys和Fragments使用ListView的。本教程是基于Eclipse4.4,Java的1.7和Android5.0。目录1.Android和Lists1.1。在Android中使用Lists1.2。Viewsforhandlinglists1.3。lists中可能的输入类型1.4。适配器1.5。过滤和排序1.6。adapter中的数据更新1.7。listener(监听)2.默认adapter2.1。平台默认adapter2.2。使用ArrayAdapter2.3。使用ArrayAdapter的ListView示例3.自定义实现Adapter3.1。开发自定义adapter3.2。为list准备item布局3.3。自定义adapter示例3.4。更新adapter中的数据模型4.ListActivity和ListFragment4.1。使用ListView的默认容器4.2。ListActivity和自定义布局4.3。空list用作占位5.练习:使用ListView和ListActivity6.运动:给ListActivity添加自己的布局7.教程:实现自己的adapter8.ListViews性能篇8.1。motivation(翻译成“动机”?^_^)8.2。耗时操作8.3。避免布局臃肿和对象的创建8.4。ViewHolder模式8.5。示例9.保存selectionofaview10.ListViews中的上下文actionmode11.执行撤销操作11.1。当你想要提供一个撤消操作?11.2。示例12.性能优化13教程:如何在ListView中显示两个item14.ListView多选操作14.1。数据模型和ListView交互14.2。教程:领域模型和行的交互15.实现可扩展开的ListView15.1。ExpandableListView15.2。ExpandableListView示例16.教程:其他16.1。为item添加longclick监听器16.2。header和footer17.SimpleCursorAdapter18.其他开源库19.关于本网站19.1。捐赠支持免费教程19.2。提问和讨论19.3。授权本教程及其代码20.链接和文学20.1。源代码20.2。ListView的资源20.3。vogella资源1.AndroidandLists
1.1.UsinglistsinAndroid
Thedisplayofelementsinalistisaverycommonpatterninmobileapplications.Theuserseesalistofitemsandcanscrollthroughthem.Suchanactivityisdepictedinthefollowingpicture.在移动应用中以非常普通的模式显示list中的item。用户可以滚动他们看到的list。如下图。1.2.Viewsforhandlinglists
AndroidprovidestheListViewandthe
ExpandableListViewclasseswhichiscapableofdisplayingascrollablelistofitems.The
ExpandableListViewclasssupportsagroupingofitems.Android提供了ListView和ExpandableListView能够显示和滚动lists的item。ExpandableListView类支持的item的分组。
1.3。对于列出了可能的输入类型
Theinputtothelist(itemsinthelist)canbearbitraryJavaobjects.TheadapterextractsthecorrectdatafromthedataobjectandassignsthisdatatotheviewsintherowoftheListView.Theseitemsaretypicallycalledthedatamodelofthelist.Anadaptercanreceivedataasinput.List的item可以显示任意的Java对象。adatper从数据对象中提取正确的数据,并显示到list的item中的views中。这些items通常被称为列表的数据模型。适配器可以接收数据作为输入。
1.4。适配器
Anadaptermanagesthedatamodelandadaptsittotheindividualentriesinthewidget.AnadapterextendstheBaseAdapterclass.Everylineinthewidgetdisplayingthedataconsistsofalayoutwhichcanbeascomplexasyouwant.Atypicallineinalisthasanimageontheleftsideandtwotextlinesinthemiddleasdepictedinthefollowinggraphic.适配器管理数据模型,将数据放入widget中。适配器继承自BaseAdapter类。显示数据的widget中可以使用任意只要你想要的复杂布局。在一个列表中一个典型的线对的左侧和在如以下图形所示的中间两个文本行图像。Alayoutfileforasuchalinemightlooklikethefollowing.对于这样的布局文件就像下面这样:
getView()methodandassignthedatatotheindividualviewsintherow.Theadapterisassignedtothe
ListViewviathe
setAdaptermethodonthe
ListViewobject.
1.5.Filteringandsorting
Filteringandsortingofthedataishandledbytheadapter.Youneedtoimplementthelogicinyourcustomadapterimplementation.数据的过滤和排序由适配器处理。你只需要实现自定义适配器的逻辑。1.6.Dataupdatesintheadapter
ThenotifyDataSetChanged()methodontheadapteriscalledifthedatahaschangedorifnewdataisavailable.The
notifyDataSetInvalidated()methodiscalledifthedataisnotavailableanymore.如果数据已经改变或者有新的数据可用,适配器应该调用
notifyDataSetChanged()如果数据不再可用,应当调用notifyDataSetInvalidated()方法
1.7.Listener
Toreacttoselectionsinthelist,setanOnItemClickListenertoyour
ListView.为item设置点击OnItemClickListener
2.Defaultadapter
2.1.Defaultplatformadapter
Androidprovidesdefaultadapterimplementations;themostimportantareArrayAdapterand
CursorAdapter.
ArrayAdaptercanhandledatabasedon
Arraysor
java.util.List.
SimpleCursorAdaptercanhandledatabaserelateddata.Android提供了默认的适配器的实现;最重要的是
ArrayAdapter和
CursorAdapter。
ArrayAdapter可以处理基于
Arrays或
java.util.List的数据。
SimpleCursorAdapter可以处理数据库的相关数据。
2.2.UsingArrayAdapter
TheArrayAdapterclasscanhandlealistorarrayofJavaobjectsasinput.EveryJavaobjectismappedtoonerow.Bydefault,itmapsthe
toString()methodoftheobjecttoaviewintherowlayout.YoucandefinetheIDoftheviewintheconstructorofthe
ArrayAdapterotherwisethe
android.R.id.text1IDisusedasdefault.The
ArrayAdapterclassallowstoremoveallelementsinitsunderlyingdatastructurewiththe
clear()methodcall.Youcanthenaddnewelementsviathe
add()methodora
Collectionviathe
addAll()method.Youcanalsodirectlymodifytheunderlyingdatastructureandcallthe
notifyDataSetChanged()methodontheadaptertonotifyitaboutthechangesindata.
ArrayAdapter类可以处理Java对象作为输入列表或数组。每个Java对象映射到一行。默认情况下,它映射
toString()对象的方法,在该行布局视图。您可以定义在的构造函数的视图的ID
ArrayAdapter否则
android.R.id.text1ID被用作默认。在
ArrayAdapter类可删除其底层数据结构中的所有元素与
clear()方法调用。然后,您可以通过添加新元素
add()方法或
Collection通过
addAll()方法。您也可以直接修改底层的数据结构,并调用
notifyDataSetChanged()的适配器上的方法,通知它有关的变化数据。
2.3.ListViewexamplewithArrayAdapter
Thefollowinglistingshowsalayoutfilecalledactivity_listviewexampleactivity.xmlwhichincludesa
ListView.
ListViewviewinanactivity.ItusesadefaultlayoutfromtheAndroidplatformfortherowlayout.Italsodemonstratestheremovaloflistitemsandusesanimationsfortheremoval.
3.Customadapterimplementations
3.1.Developingacustomadapter
TheArrayAdapterislimitedasitsupportsonlythemappingof
toString()tooneviewintherowlayout.Tocontrolthedataassignmentandtosupportseveralviews,youhavetocreateyourcustomadapterimplementation.Forthisyouwouldextendanexistingadapterimplementationorsubclassthe
BaseAdapterclassdirectly.
Tip
FrequentlyyouextendArrayAdaptertowriteacustomadapter,asthisissimplerthanextending
BaseAdapterdirectly.所述
ArrayAdapter有限,因为它支持的唯一映射
toString()中的行布局1图。来控制数据的分配,并支持多个视图,你必须创建自己的自定义适配器实现。为此,将扩大现有的适配器实现或子类
BaseAdapter直接类。
尖
经常要扩展ArrayAdapter编写自定义适配器,因为这是不是扩展简单
BaseAdapter直接。
3.2.Preparingarowforthelist
Theadapterneedstocreatealayoutforeachrowofthelist.TheListViewinstancecallsthe
getView()methodontheadapterforeachdataelement.Inthismethodtheadaptercreatestherowlayoutandmapsthedatatotheviewsinthelayout.Thisrootofthelayoutistypicallya
ViewGroup(layoutmanager)andcontainsseveralotherviews,e.g.,an
ImageViewanda
TextView.Thefollowinggraphicshowsalistwithdifferentlayoutsforoddandevenrows.该适配器需要创建一个布局为列表中的每一行。所述
ListView实例调用
getView()为每个数据元素在适配器上的方法。在该方法中,适配器创建的行布局和数据映射到在布局的观点。布局的这根通常是
ViewGroup(布局管理器),并包含一些其他意见,例如,一个
ImageView和
TextView。下图显示了不同的布局奇数行和偶数行的列表。
getView()methodyouwouldinflateanXMLbasedlayoutandthensetthecontentoftheindividualviewsbasedontheJavaobjectforthisrow.ToinflatetheXMLlayoutfile,youcanusethe
LayoutInflatorsystemservice.
Note
ThislayoutinflatorservicecangetaccessedviathegetLayoutInflator()methodoftheactivityorviathe
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)methodcall.Aftertheadapterinflatedthelayout,itsearchesfortherelevantviewsinthelayoutandfillsthemwiththedata.Theindividualelementsinthelayoutcanbefoundviathe
findViewById()methodcallonthetoplevelview.
在
getView()方法内,你会助长一种基于XML的布局,然后设置基于此行的Java对象的个人意见的内容。膨胀的XML布局文件,你可以使用
LayoutInflator系统服务。
注意
这种布局充气机服务可以通过获得访问getLayoutInflator()活动的方法或通过
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)方法调用。后适配器膨胀的布局,它搜索的布局有关意见,并填写他们的数据。在布局中的各个元件可以通过找到
findViewById()上的顶层视图方法调用。
3.3.Exampleforacustomadapter
Thefollowingcodeshowsanimplementationofacustomadapter.Thisadapterassumesthatyouhavetwopngfiles(no.pngandyes.png)inoneofyourres/drawablefolders.ThecodinginflatesanXMLlayoutfile,findstherelevantviewsinthelayoutandsetstheircontentbasedontheinputdata.下面的代码显示了一个自定义适配器的实现。这个适配器假设你在一个有两个png文件(no.png和yes.png)
res/drawable文件夹。编码膨胀的XML布局文件,找到有关的意见,在布局,并基于所述输入数据的内容。
3.4.Updatingthedatamodelfromtheadapter
Therowcanalsocontainviewswhichinteractwiththeunderlyingdatamodelviatheadapter.Forexample,youcanhaveaCheckboxinyourrowlayoutandifthe
Checkboxisselected,theunderlyingdataischanged.复制真累,后面的一次性贴上了,上下翻动着看吧~~~啊啊啊啊啊啊啊,英文差的悲催娃,翻译个文章都翻译不了~~
4.ListActivityandListFragment
4.1.DefaultcontainerforusingListView
Androidprovidesspecializedfragmentandactivityclassestosimplifylisthandling.TheclassesaretheListActivityclassifyouwanttouselistsinactivitiesandthethe
ListFragmentclassifyouwanttouselistsinfragments.Youdonothavetoassignalayouttotheseelements.Ifyoudonotdefinealayout,theactivityorfragmentcontainsasingle
ListViewbydefault.
ListActivityand
ListFragmentalsoallowyoutooverridea
onListItemClick()methodforhandlingselectionoflistitems.Bothclassesallowyoutosettheadaptertothedefault
ListViewviathe
setListAdapter()method.Thefollowingexamplecodeshowsasimple
ListFragmentimplementation.
packagede.vogella.android.fragments; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.app.ListFragment; publicclassMyListFragmentextendsListFragment{ @Override publicvoidonActivityCreated(BundlesavedInstanceState){ super.onActivityCreated(savedInstanceState); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,values); setListAdapter(adapter); } @Override publicvoidonListItemClick(ListViewl,Viewv,intposition,longid){ //dosomethingwiththedata } }Thenextexamplecodedemonstratestheusageofa
ListActivity.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; publicclassMyListActivityextendsListActivity{ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_1,values); setListAdapter(adapter); } }
4.2.ListActivityandcustomlayout
YoucanuseacustomlayoutwithListActivityor
ListFragment.Inthiscasethefragmentoractivitysearchesintheprovidedlayoutfora
ListViewwiththepre-defined
android:idattributesetto
@android:id/list.Thisusageisdemonstratedbythefollowingcodesnippet.
<ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView>
Warning
IfyoudonotusethisIDordonotincludeaListViewintoyourlayout,theapplicationcrashesonceyoutrytodisplaytheactivityorthefragment.
4.3.Placeholderforanemptylist
Youcanalsouseaviewwiththe@android:id/emptyIDinyourlayout.Thecorrespondingactivityandfragmentshowsthisviewautomaticallyifthe
ListViewisemptyandhidesitotherwise.Forexample,youcoulddisplayanerrormessageinsuchaview.
5.Exercise:UsingListViewandListActivity
ThefollowingexercisedemonstrateshowtouseaListViewinan
ListActivity.Youusethepredefined
ArrayAdapterclassandanexistingAndroidlayoutfortherows.CreateanewAndroidprojectcalledde.vogella.android.listactivitywiththeactivitycalled
MyListActivity.Change
MyListActivityclassbasedonthethefollowingcodeexample.Notethatthe
setContentView()methodisnotused.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; publicclassMyListActivityextendsListActivity{ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_1,values); setListAdapter(adapter); } @Override protectedvoidonListItemClick(ListViewl,Viewv,intposition,longid){ Stringitem=(String)getListAdapter().getItem(position); Toast.makeText(this,item+"selected",Toast.LENGTH_LONG).show(); } }
6.Exercise:ListActivitywithownlayout
Inourexampleyourwilldefineyourlayoutfortherowsanduseitinyouradapter.Createtherowlayout.xmllayoutfileinthe
res/layoutfolderofthe
de.vogella.android.listactivityproject.
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/icon" android:layout_width="22px" android:layout_height="22px" android:layout_marginLeft="4px" android:layout_marginRight="10px" android:layout_marginTop="4px" android:src="@drawable/ic_launcher"> </ImageView> <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@+id/label" android:textSize="20px"> </TextView> </LinearLayout>Changeyouractivitysothatisusingthenewlayout.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; publicclassMyListActivityextendsListActivity{ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; //useyourcustomlayout ArrayAdapter<String>adapter=newArrayAdapter<String>(this, R.layout.rowlayout,R.id.label,values); setListAdapter(adapter); } @Override protectedvoidonListItemClick(ListViewl,Viewv,intposition,longid){ Stringitem=(String)getListAdapter().getItem(position); Toast.makeText(this,item+"selected",Toast.LENGTH_LONG).show(); } }
7.Tutorial:Implementingyourownadapter
Thefollowingusestwoimages"no.png"and"ok.png".Iplaceditinthe"res/drawable-mdpi"folder.Youmustcreateyourownicons.Incaseyoudonotfindanyiconsjustcopy"icon.png"anduseadrawingprogramtochangeitalittlebit.CreatetheclassMySimpleArrayAdapterwhichwillserveasouradapter.
packagede.vogella.android.listactivity; importandroid.content.Context; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.ArrayAdapter; importandroid.widget.ImageView; importandroid.widget.TextView; publicclassMySimpleArrayAdapterextendsArrayAdapter<String>{ privatefinalContextcontext; privatefinalString[]values; publicMySimpleArrayAdapter(Contextcontext,String[]values){ super(context,R.layout.rowlayout,values); this.context=context; this.values=values; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ LayoutInflaterinflater=(LayoutInflater)context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewrowView=inflater.inflate(R.layout.rowlayout,parent,false); TextViewtextView=(TextView)rowView.findViewById(R.id.label); ImageViewimageView=(ImageView)rowView.findViewById(R.id.icon); textView.setText(values[position]); //ChangetheiconforWindowsandiPhone Strings=values[position]; if(s.startsWith("Windows7")||s.startsWith("iPhone") ||s.startsWith("Solaris")){ imageView.setImageResource(R.drawable.no); }else{ imageView.setImageResource(R.drawable.ok); } returnrowView; } }Tousethisadapter,changetheactivitytothefollowing.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; publicclassMyListActivityextendsListActivity{ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; MySimpleArrayAdapteradapter=newMySimpleArrayAdapter(this,values); setListAdapter(adapter); } }Ifyourunthisexampleyoushouldgetalistwithdifferenticonsforthecertainelements.
8.ListViewsandperformance
8.1.Motivation
PerformanceisespeciallyimportantonAndroidasusersexpectfastreactiontimes.ComparedtodesktopcomputersanAndroiddeviceisrelativelyslowfromthehardwareperspective.Thispartdescribeshowtoreducetheseoperationstoimplementyourcustomlistadapterefficiently.ThedefaultAndroidadapterslikeArrayAdapterarealreadyperformanceoptimized.
8.2.Timeconsumingoperations
EveryviewwhichgetinflatedfromanXMLlayoutfilewillresultinaJavaobject.InflatinglayoutsandcreatingJavaobjectsisexpensivewithregardstotimeandmemoryconsumption.InadditionusingthefindViewById()methodisrelativelytimeconsuming,eventhoughitisnotasbadasXMLinflating.
8.3.Avoidinglayoutinflationandobjectcreation
AListViewtypicallycontainsmoredatathanthenumberofdisplayedrows.Iftheuserscrollsthelist,thenrowsandtheirassociatedviewsarebeingscrolledoutofthevisiblearea.TheJavaobjectswhichrepresentstherowscanbereusedfornewlyvisiblerows.IfAndroiddeterminesthatarowisnotvisibleanymore,itallowsthe
getView()oftheadaptermethodtoreusetheassociatedviewviathe
convertViewparameter.Theadaptercanassignnewdatatotheviewscontainedintheviewhierarchyofthe
convertView.ThisavoidsinflatinganXMLfileandcreatingnewJavaobjects.IncaseAndroidcannotreusearow,theAndroidsystempasses
nulltothe
convertViewparameter.Thereforetheadapterimplementationneedstocheckforthis.
8.4.Viewholderpattern
***iewHolderimplementationallowstoavoidthefindViewById()methodinanadapter.A
ViewHolderclassistypicallyastaticinnerclassinyouradapterwhichholdsreferencestotherelevantviews.inyourlayout.Thisreferenceisassignedtotherowviewasatagviathe
setTag()method.Ifwereceivea
convertViewobject,wecangettheinstanceofthe
ViewHolderviathe
getTag()methodandassignthenewattributestotheviewsviathe
ViewHolderreference.Whilethissoundscomplexthisisapproximately15%fasterthenusingthe
findViewById()method.
8.5.Example
Thefollowingcodeshowsaperformanceoptimizedadapterimplementationwhichreusesexistingviewsandimplementstheholderpattern.packagede.vogella.android.listactivity; importandroid.app.Activity; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.ArrayAdapter; importandroid.widget.ImageView; importandroid.widget.TextView; publicclassMyPerformanceArrayAdapterextendsArrayAdapter<String>{ privatefinalActivitycontext; privatefinalString[]names; staticclassViewHolder{ publicTextViewtext; publicImageViewimage; } publicMyPerformanceArrayAdapter(Activitycontext,String[]names){ super(context,R.layout.rowlayout,names); this.context=context; this.names=names; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ViewrowView=convertView; //reuseviews if(rowView==null){ LayoutInflaterinflater=context.getLayoutInflater(); rowView=inflater.inflate(R.layout.rowlayout,null); //configureviewholder ViewHolderviewHolder=newViewHolder(); viewHolder.text=(TextView)rowView.findViewById(R.id.TextView01); viewHolder.image=(ImageView)rowView .findViewById(R.id.ImageView01); rowView.setTag(viewHolder); } //filldata ViewHolderholder=(ViewHolder)rowView.getTag(); Strings=names[position]; holder.text.setText(s); if(s.startsWith("Windows7")||s.startsWith("iPhone") ||s.startsWith("Solaris")){ holder.image.setImageResource(R.drawable.no); }else{ holder.image.setImageResource(R.drawable.ok); } returnrowView; } }
9.Storingtheselectionofaview
BydefaultaListViewhasnoselectionmodeactive.Youcanactivateitviathe
setChoiceMode()methodcall.Pass
ListView.CHOICE_MODE_MULTIPLEformultipleselectionsor
ListView.CHOICE_MODE_SINGLEforsingleselectionstothismethod.Togettheselecteditemsofa
ListView,usethe
getCheckedItemPosition()forasingleselectionmethodor
listView.getCheckedItemPositions()formultipleselections..IfyouhavestableID,youcouldalsousethe
getCheckedItemIds()methodtogettheselectedIDs.Androidalreadyprovidesadefaultlayoutforthis:the
android.R.layout.simple_list_item_multiple_choicelayoutwhichcontainsaconfigured
CheckedTextViewview.Thefollowingactivitiesdemonstratehowtousetheseselectionmodes.Ifyouusethesemodes,the
ListViewstorestheselectedvalues.Itisnotpersistedinyourdatamodel.
packagecom.vogella.android.listview.selection.multi; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; importcom.vogella.android.listview.selection.R; publicclassMainActivityextendsListActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); String[]values=newString[]{"a","b","c","d","e","f","g", "h","i","j","k","l","m","n","o","p","q","r","s", "t","u","w","x","y","z"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice,values); setListAdapter(adapter); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); } @Override publicbooleanonCreateOptionsMenu(Menumenu){ getMenuInflater().inflate(R.menu.main,menu); returntrue; } @Override publicbooleanonOptionsItemSelected(MenuItemitem){ Toast.makeText(this, String.valueOf(getListView().getCheckedItemCount()), Toast.LENGTH_LONG).show(); returntrue; } }
packagecom.vogella.android.listview.selection.single; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; publicclassMainActivityextendsListActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); String[]values=newString[]{"a","b","c","d","e","f","g", "h","i","j","k","l","m","n","o","p","q","r","s", "t","u","w","x","y","z"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice,values); setListAdapter(adapter); getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); } @Override publicbooleanonCreateOptionsMenu(Menumenu){ getMenuInflater().inflate(R.menu.main,menu); returntrue; } @Override publicbooleanonOptionsItemSelected(MenuItemitem){ Toast.makeText(this, String.valueOf(getListView().getCheckedItemCount()), Toast.LENGTH_LONG).show(); returntrue; } }
10.ContextualactionmodeforListViews
ThefollowingassumesthatyoualreadyfamiliarwiththeconceptoftheActionBarandcontextualactionmodeingeneral.ThispartwillexplainhowtousecontextualactionmodeforaListViewselection.Toassignacontextualactionmodetoalongclickonanindividualitem,usethemethod
setOnItemLongClickListener()on
ListView.Thismethodsincludesinformationabouttheselecteditem.Inthismethodyoucanstartthe
ActionMode.Thefollowingexamplesdemonstratethat.ItassumesthatyouhaveamenuXMLfiledefinedcalled
rowselection.xmlandthatthismenucontainsoneentrywiththe
@+id/menuitem1_showID.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.ActionMode; importandroid.view.Menu; importandroid.view.MenuInflater; importandroid.view.MenuItem; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemLongClickListener; importandroid.widget.Toast; publicclassMyListActivityActionbarextendsListActivity implementsActionMode.Callback{ protectedObjectmActionMode; publicintselectedItem=-1; @Override publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android", "iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu", "Windows7","MaxOSX","Linux","OS/2", "Ubuntu","Windows7","MaxOSX", "Linux","OS/2","Ubuntu", "Windows7","MaxOSX", "Linux","OS/2"}; MySimpleArrayAdapteradapter=newMySimpleArrayAdapter(this,values); setListAdapter(adapter); getListView().setOnItemLongClickListener(newOnItemLongClickListener(){ @Override publicbooleanonItemLongClick(AdapterView<?>parent,Viewview,intposition,longid){ if(mActionMode!=null){ returnfalse; } selectedItem=position; //StarttheCABusingtheActionMode.Callbackdefinedabove MyListActivityActionbar.this.startActionMode(MyListActivityActionbar.this); view.setSelected(true); returntrue; } }); } privatevoidshow(){ Toast.makeText(MyListActivityActionbar.this,String.valueOf(selectedItem),Toast.LENGTH_LONG).show(); } //Calledwhentheactionmodeiscreated;startActionMode()wascalled @Override publicbooleanonCreateActionMode(ActionModemode,Menumenu){ //Inflateamenuresourceprovidingcontextmenuitems MenuInflaterinflater=mode.getMenuInflater(); //Assumesthatyouhave"contexual.xml"menuresources inflater.inflate(R.menu.rowselection,menu); returntrue; } //Calledeachtimetheactionmodeisshown.Alwayscalledafter //onCreateActionMode,but //maybecalledmultipletimesifthemodeisinvalidated. @Override publicbooleanonPrepareActionMode(ActionModemode,Menumenu){ returnfalse;//Returnfalseifnothingisdone } //Calledwhentheuserselectsacontextualmenuitem @Override publicbooleanonActionItemClicked(ActionModemode,MenuItemitem){ switch(item.getItemId()){ caseR.id.menuitem1_show: show(); //Actionpicked,soclosetheCAB mode.finish(); returntrue; default: returnfalse; } } //Calledwhentheuserexitstheactionmode @Override publicvoidonDestroyActionMode(ActionModemode){ mActionMode=null; selectedItem=-1; } }Ifyoustartyourapplicationandlongpressonaniteminthelist,yougetyourcontextualactionbar.
11.Implementingundoforanaction
11.1.Whenshouldyouofferanundoaction?
Itisgoodpracticetoallowtheusertoundocriticalactions.Suchacriticalactionis,forexample,thedeletionoflistitems.Aprovenpatterntohandlethisundooptionistoofferaselectionattheendofthescreen.Thisselectionvanishesafterapredefinedtimeoroncetheusercontinuestointeractwiththeapplication.Forexample,theGmailapplicationimplementssuchabehavior.11.2.Example
Thefollowingdescriptioncontainsanexampleforimplementinganundoaction.Itusesananimationtophaseouttheundobuttonautomaticallyoutafterawhile.Forthisexamplecreateanewprojectcalledcom.vogella.android.userinterface.undobasedontheBlankTemplatetemplate.Createthefollowinglayoutforyouractivity.ItusesaFrameLayouttoshowtwodifferentpartsoftheuserinterface.Thebuttonbarisinitiallyhidden.Thebuttonusesadrawable.Eitheraddsuchadrawabletoyourprojectorremovethereference.
<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </RelativeLayout> <LinearLayout android:id="@+id/undobar" android:visibility="gone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:layout_margin="20dp" android:alpha="100" android:background="#808080" android:dividerPadding="11dp" android:padding="4dp"> <TextView android:id="@+id/undobar_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Deleted" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="#fff"/> <Button android:id="@+id/undobar_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:onClick="onClick" android:background="#808080" android:drawableLeft="@drawable/ic_undobar_undo" android:text="Undo" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="#fff"/> </LinearLayout> </FrameLayout>Changeyouractivitysothatitissimilartothefollowingcode.TheAndroidprojectwizardinEclipsealreadygeneratedan
ActionBarentry.Thisentryisusedinthefollowingcode.Ifindoubt,createyourown
ActionBarentry.
packagecom.vogella.android.userinterface.undo; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.view.View; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; importcom.vogella.android.actionbar.undo.R; publicclassMainActivityextendsActivity{ privateViewviewContainer; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListViewl=(ListView)findViewById(R.id.listview); String[]values=newString[]{"Ubuntu","Android","iPhone", "Windows","Ubuntu","Android","iPhone","Windows"}; ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_1,values); viewContainer=findViewById(R.id.undobar); l.setAdapter(adapter); } @Override publicbooleanonCreateOptionsMenu(Menumenu){ //Inflatethemenu;thisaddsitemstotheactionbarifitispresent. getMenuInflater().inflate(R.menu.activity_main,menu); returntrue; } @Override publicbooleanonOptionsItemSelected(MenuItemitem){ showUndo(viewContainer); returntrue; } publicvoidonClick(Viewview){ Toast.makeText(this,"Deletionundone",Toast.LENGTH_LONG).show(); viewContainer.setVisibility(View.GONE); } publicstaticvoidshowUndo(finalViewviewContainer){ viewContainer.setVisibility(View.VISIBLE); viewContainer.setAlpha(1); viewContainer.animate().alpha(0.4f).setDuration(5000) .withEndAction(newRunnable(){ @Override publicvoidrun(){ viewContainer.setVisibility(View.GONE); } }); } }IfyouselecttheentryintheActionBar,thebuttonbarbecomesvisiblefor5seconds.
12.PerformanceOptimization
Thefollowingwillimplementaperformanceoptimizedversionoftheadapterfromthepreviousexample.CreatethefollowingMyPerformanceArrayAdapterclass.
packagede.vogella.android.listactivity; importandroid.app.Activity; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.ArrayAdapter; importandroid.widget.ImageView; importandroid.widget.TextView; publicclassMyPerformanceArrayAdapterextendsArrayAdapter<String>{ privatefinalActivitycontext; privatefinalString[]names; staticclassViewHolder{ publicTextViewtext; publicImageViewimage; } publicMyPerformanceArrayAdapter(Activitycontext,String[]names){ super(context,R.layout.rowlayout,names); this.context=context; this.names=names; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ViewrowView=convertView; //reuseviews if(rowView==null){ LayoutInflaterinflater=context.getLayoutInflater(); rowView=inflater.inflate(R.layout.rowlayout,null); //configureviewholder ViewHolderviewHolder=newViewHolder(); viewHolder.text=(TextView)rowView.findViewById(R.id.TextView01); viewHolder.image=(ImageView)rowView .findViewById(R.id.ImageView01); rowView.setTag(viewHolder); } //filldata ViewHolderholder=(ViewHolder)rowView.getTag(); Strings=names[position]; holder.text.setText(s); if(s.startsWith("Windows7")||s.startsWith("iPhone") ||s.startsWith("Solaris")){ holder.image.setImageResource(R.drawable.no); }else{ holder.image.setImageResource(R.drawable.ok); } returnrowView; } }Useyournewadapterinyouractivity.Ifyouruntheapplicationitshouldlookthesamebutitwillbemuchfaster,especiallyforlargedatasets.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; publicclassMyListActivityextendsListActivity{ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); String[]values=newString[]{"Android","iPhone","WindowsMobile", "Blackberry","WebOS","Ubuntu","Windows7","MaxOSX", "Linux","OS/2"}; setListAdapter(newMyPerformanceArrayAdapter(this,values)); } }
13.Tutorial:HowtodisplaytwoitemsinaListView
YoucanusetheSimpleAdapterclasstoshowthedataoftwoelements.ThisclassexpectsaArrayofStrings(
fromdata)inwhichthefieldsoftheinputdataaredefined.ItalsorequiresaArrayofintswhichdefinestheIDsofthewidgetsinthelayoutfortherowtowhichthesefieldsaremapped.TheactualdataisthenalistofMaps.TheMapdefinesforeachfieldinthefromdataavalue.ThefollowingshowsanexamplewhichreusesanpredefinedlayoutfromAndroidfortherow.
packagede.vogella.android.listactivity; importjava.util.ArrayList; importjava.util.HashMap; importjava.util.Map; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.widget.SimpleAdapter; publicclassMyTwoListItemsActivityextendsListActivity{ protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); ArrayList<Map<String,String>>list=buildData(); String[]from={"name","purpose"}; int[]to={android.R.id.text1,android.R.id.text2}; SimpleAdapteradapter=newSimpleAdapter(this,list, android.R.layout.simple_list_item_2,from,to); setListAdapter(adapter); } privateArrayList<Map<String,String>>buildData(){ ArrayList<Map<String,String>>list=newArrayList<Map<String,String>>(); list.add(putData("Android","Mobile")); list.add(putData("Windows7","Windows7")); list.add(putData("iPhone","iPhone")); returnlist; } privateHashMap<String,String>putData(Stringname,Stringpurpose){ HashMap<String,String>item=newHashMap<String,String>(); item.put("name",name); item.put("purpose",purpose); returnitem; } }
14.SelectingmultipleitemsintheListView
14.1.InteractionbetweenthemodelandListview
FrequentlyyouneedtoselectitemsinyourListView.Astherowofthe
ListViewaregettingrecycledyoucannotstoretheselectiononthe
Viewlevel.
ListViewyoudefineyourown
Adapterclass.Inthisadapterclassyouattachalistenertothe
Viewwhichisresponsibleforselectingthemodelelement.IfselectedyouupdatethestateinthemodelwhichyoucanaddasatagtotheViewtohaveaccesstoit.ThefollowingexampledemonstrateshowtousestandardJavaobjectandhowtointeractfromthe
Viewswiththemodel.
14.2.Tutorial:DomainModelandRowsinteraction
Continuetousethede.vogella.android.listactivityproject.Createthefollowing
Modelwhichholdthenameandtheinformationifthiselementiscurrentlyselected.
packagede.vogella.android.listactivity; publicclassModel{ privateStringname; privatebooleanselected; publicModel(Stringname){ this.name=name; selected=false; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicbooleanisSelected(){ returnselected; } publicvoidsetSelected(booleanselected){ this.selected=selected; } }Createthefollowingnewlayoutfilecalled
rowbuttonlayout.xml.
<?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@+id/label" android:textSize="30px"> </TextView> <CheckBox android:id="@+id/check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginLeft="4px" android:layout_marginRight="10px"> </CheckBox> </RelativeLayout>Createthefollowing
Adapter.Thisadapteraddsalisteneronthe
Checkboxview.Ifthecheckboxisselectedtheunderlyingdataofthemodelischanged.
Checkboxgetsthecorrespondingmodelelementassignedviathe
getTag()method.
packagede.vogella.android.listactivity; importjava.util.List; importandroid.app.Activity; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.ArrayAdapter; importandroid.widget.CheckBox; importandroid.widget.CompoundButton; importandroid.widget.TextView; publicclassInteractiveArrayAdapterextendsArrayAdapter<Model>{ privatefinalList<Model>list; privatefinalActivitycontext; publicInteractiveArrayAdapter(Activitycontext,List<Model>list){ super(context,R.layout.rowbuttonlayout,list); this.context=context; this.list=list; } staticclassViewHolder{ protectedTextViewtext; protectedCheckBoxcheckbox; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ Viewview=null; if(convertView==null){ LayoutInflaterinflator=context.getLayoutInflater(); view=inflator.inflate(R.layout.rowbuttonlayout,null); finalViewHolderviewHolder=newViewHolder(); viewHolder.text=(TextView)view.findViewById(R.id.label); viewHolder.checkbox=(CheckBox)view.findViewById(R.id.check); viewHolder.checkbox .setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){ @Override publicvoidonCheckedChanged(CompoundButtonbuttonView, booleanisChecked){ Modelelement=(Model)viewHolder.checkbox .getTag(); element.setSelected(buttonView.isChecked()); } }); view.setTag(viewHolder); viewHolder.checkbox.setTag(list.get(position)); }else{ view=convertView; ((ViewHolder)view.getTag()).checkbox.setTag(list.get(position)); } ViewHolderholder=(ViewHolder)view.getTag(); holder.text.setText(list.get(position).getName()); holder.checkbox.setChecked(list.get(position).isSelected()); returnview; } }Finallychangeyouractivitytothefollowing.
packagede.vogella.android.listactivity; importjava.util.ArrayList; importjava.util.List; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; publicclassMyListextendsListActivity{ /**Calledwhentheactivityisfirstcreated.*/ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); //createanarrayofStrings,thatwillbeputtoourListActivity ArrayAdapter<Model>adapter=newInteractiveArrayAdapter(this, getModel()); setListAdapter(adapter); } privateList<Model>getModel(){ List<Model>list=newArrayList<Model>(); list.add(get("Linux")); list.add(get("Windows7")); list.add(get("Suse")); list.add(get("Eclipse")); list.add(get("Ubuntu")); list.add(get("Solaris")); list.add(get("Android")); list.add(get("iPhone")); //Initiallyselectoneoftheitems list.get(1).setSelected(true); returnlist; } privateModelget(Strings){ returnnewModel(s); } }Ifyoustartyourappyoushouldbeabletoflagitems.Thesechangeswillbereflectedinyourmodel.
15.ImplementinganexpandableListView
15.1.ExpandableListView
TheExpandableListViewissimilarto
ListViewbutallowyoutodefinegroupsanddetailsforthisgroup.
ExpandableListViewexpectsandadapteroftype
BaseExpandableListAdapter.Inthiscaseyouhavetodefinetwolayouts,oneforthegroupandanotheroneforthedetailsrow.
15.2.ExpandableListViewexample
Inthefollowingexampleyoucreateanexpandablelistviewsimilartothefollowingscreenshot.MainActivity.Createoradjustthefollowinglayoutfiles.First
layout/activity_main.xml.
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ExpandableListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content"> </ExpandableListView> </LinearLayout>Afterwardscreate
layout/listrow_group.xml.
<CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="?android:attr/listPreferredItemHeight" android:layout_marginLeft="8dp" android:drawableRight="@drawable/ic_launcher" android:gravity="left" android:paddingLeft="32dp" android:paddingTop="8dp" android:text="Test" android:textSize="14sp" android:textAlignment="textEnd" android:textStyle="bold"/>Thelastrequiredlayoutis
layout/listrow_details.xml.
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="40dp" android:clickable="true" android:orientation="vertical" android:paddingLeft="40dp" tools:context=".MainActivity"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/ic_launcher" android:drawablePadding="5dp" android:gravity="center_vertical" android:text="@string/hello_world" android:textSize="14sp" android:textStyle="bold"> </TextView> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black"/> </LinearLayout>Createthefollowingclasswhichholdyourdomainmodelforthe
ExpandableListView.
packagecom.vogella.android.listview.expandable; importjava.util.ArrayList; importjava.util.List; publicclassGroup{ publicStringstring; publicfinalList<String>children=newArrayList<String>(); publicGroup(Stringstring){ this.string=string; } }Finallycreatetheadapterasdescribedbythefollowinglistingandchangetheactivitytothecodeprovidedbelow.
packagecom.vogella.android.listview.expandable; importandroid.app.Activity; importandroid.util.SparseArray; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.view.ViewGroup; importandroid.widget.BaseExpandableListAdapter; importandroid.widget.CheckedTextView; importandroid.widget.TextView; importandroid.widget.Toast; publicclassMyExpandableListAdapterextendsBaseExpandableListAdapter{ privatefinalSparseArray<Group>groups; publicLayoutInflaterinflater; publicActivityactivity; publicMyExpandableListAdapter(Activityact,SparseArray<Group>groups){ activity=act; this.groups=groups; inflater=act.getLayoutInflater(); } @Override publicObjectgetChild(intgroupPosition,intchildPosition){ returngroups.get(groupPosition).children.get(childPosition); } @Override publiclonggetChildId(intgroupPosition,intchildPosition){ return0; } @Override publicViewgetChildView(intgroupPosition,finalintchildPosition, booleanisLastChild,ViewconvertView,ViewGroupparent){ finalStringchildren=(String)getChild(groupPosition,childPosition); TextViewtext=null; if(convertView==null){ convertView=inflater.inflate(R.layout.listrow_details,null); } text=(TextView)convertView.findViewById(R.id.textView1); text.setText(children); convertView.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ Toast.makeText(activity,children, Toast.LENGTH_SHORT).show(); } }); returnconvertView; } @Override publicintgetChildrenCount(intgroupPosition){ returngroups.get(groupPosition).children.size(); } @Override publicObjectgetGroup(intgroupPosition){ returngroups.get(groupPosition); } @Override publicintgetGroupCount(){ returngroups.size(); } @Override publicvoidonGroupCollapsed(intgroupPosition){ super.onGroupCollapsed(groupPosition); } @Override publicvoidonGroupExpanded(intgroupPosition){ super.onGroupExpanded(groupPosition); } @Override publiclonggetGroupId(intgroupPosition){ return0; } @Override publicViewgetGroupView(intgroupPosition,booleanisExpanded, ViewconvertView,ViewGroupparent){ if(convertView==null){ convertView=inflater.inflate(R.layout.listrow_group,null); } Groupgroup=(Group)getGroup(groupPosition); ((CheckedTextView)convertView).setText(group.string); ((CheckedTextView)convertView).setChecked(isExpanded); returnconvertView; } @Override publicbooleanhasStableIds(){ returnfalse; } @Override publicbooleanisChildSelectable(intgroupPosition,intchildPosition){ returnfalse; } }
packagecom.vogella.android.listview.expandable; importjava.util.ArrayList; importandroid.app.Activity; importandroid.os.Bundle; importandroid.util.SparseArray; importandroid.view.Menu; importandroid.widget.ExpandableListView; publicclassMainActivityextendsActivity{ //moreefficientthanHashMapformappingintegerstoobjects SparseArray<Group>groups=newSparseArray<Group>(); @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); createData(); ExpandableListViewlistView=(ExpandableListView)findViewById(R.id.listView); MyExpandableListAdapteradapter=newMyExpandableListAdapter(this, groups); listView.setAdapter(adapter); } publicvoidcreateData(){ for(intj=0;j<5;j++){ Groupgroup=newGroup("Test"+j); for(inti=0;i<5;i++){ group.children.add("SubItem"+i); } groups.append(j,group); } } }
16.Tutorial:Miscellaneous
16.1.Addingalongclicklistenertothelistitems
YoucanalsoaddaLongItemClickListenertothe
View.Forthisreceivethe
ListViewviathe
getListVIew()methodandsetthe
LongItemClickListenerviathesetOnItemLongClickListener()method.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemLongClickListener; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; importandroid.widget.Toast; publicclassMyListextendsListActivity{ /**Calledwhentheactivityisfirstcreated.*/ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); //createanarrayofStrings,thatwillbeputtoourListActivity String[]names=newString[]{"Linux","Windows7","Eclipse","Suse", "Ubuntu","Solaris","Android","iPhone"}; ArrayAdapter<String>adapter=newMyPerformanceArrayAdapter(this,names); setListAdapter(adapter); ListViewlist=getListView(); list.setOnItemLongClickListener(newOnItemLongClickListener(){ @Override publicbooleanonItemLongClick(AdapterView<?>parent,Viewview, intposition,longid){ Toast.makeText(MyList.this, "Iteminposition"+position+"clicked", Toast.LENGTH_LONG).show(); //Returntruetoconsumetheclickevent.Inthiscasethe //onListItemClicklistenerisnotcalledanymore. returntrue; } }); } @Override protectedvoidonListItemClick(ListViewl,Viewv,intposition,longid){ super.onListItemClick(l,v,position,id); //Gettheitemthatwasclicked Objecto=this.getListAdapter().getItem(position); Stringkeyword=o.toString(); Toast.makeText(this,"Youselected:"+keyword,Toast.LENGTH_SHORT) .show(); } }
16.2.HeaderandFooter
YoucanofcourseputarbitraryViewselementsaroundyourListView.Forexampleyoucandefinealayoutwithtwo
TextViewsanda
ListViewbetweenthem.InthiscasethetwoTextViewswillalwaysbevisibleabovetheList(header)andtheotherwillbevisiblebelowtheListView.Ifyouwanttodisplayalistheaderorlistfooteronlyattheseethebeginningorendofthelistyoucanusethe
addHeaderView()methodor
addFooterView()methodonthe
ListViewclass.
packagede.vogella.android.listactivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; publicclassMyListextendsListActivity{ /**Calledwhentheactivityisfirstcreated.*/ publicvoidonCreate(Bundleicicle){ super.onCreate(icicle); //createanarrayofStrings,thatwillbeputtoourListActivity String[]names=newString[]{"Linux","Windows7","Eclipse","Suse", "Ubuntu","Solaris","Android","iPhone","Linux","Windows7", "Eclipse","Suse","Ubuntu","Solaris","Android","iPhone"}; Viewheader=getLayoutInflater().inflate(R.layout.header,null); Viewfooter=getLayoutInflater().inflate(R.layout.footer,null); ListViewlistView=getListView(); listView.addHeaderView(header); listView.addFooterView(footer); setListAdapter(newArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, android.R.id.text1,names)); } }
17.SimpleCursorAdapter
IncaseyouworkwithacontentproviderordirectlywiththedatabaseyoucanusetheSimpleCursorAdaptertodefinethedataforyour
ListView.ThefollowingwilldemonstrateshowtoaccesstheContactsContentProvider.CreateanewAndroidprojectcalled"de.vogella.android.listactivity.cursor"withtheactivitycalledMyListActivity.Change
MyListActivitytothefollowing.
packagede.vogella.android.listactivity.cursor; importandroid.app.ListActivity; importandroid.database.Cursor; importandroid.net.Uri; importandroid.os.Bundle; importandroid.provider.ContactsContract; importandroid.widget.ListAdapter; importandroid.widget.SimpleCursorAdapter; publicclassMyListActivityextendsListActivity{ /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); CursormCursor=getContacts(); startManagingCursor(mCursor); //nowcreateanewlistadapterboundtothecursor. //SimpleListAdapterisdesignedforbindingtoaCursor. ListAdapteradapter=newSimpleCursorAdapter(this,//Context. android.R.layout.two_line_list_item,//Specifytherowtemplate //touse(here,two //columnsboundtothe //tworetrievedcursor //rows). mCursor,//Passinthecursortobindto. //Arrayofcursorcolumnstobindto. newString[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME}, //Parallelarrayofwhichtemplateobjectstobindtothose //columns. newint[]{android.R.id.text1,android.R.id.text2}); //Bindtoournewadapter. setListAdapter(adapter); } privateCursorgetContacts(){ //Runquery Uriuri=ContactsContract.Contacts.CONTENT_URI; String[]projection=newString[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME}; Stringselection=ContactsContract.Contacts.IN_VISIBLE_GROUP+"='" +("1")+"'"; String[]selectionArgs=null; StringsortOrder=ContactsContract.Contacts.DISPLAY_NAME +"COLLATELOCALIZEDASC"; returnmanagedQuery(uri,projection,selection,selectionArgs, sortOrder); } }Makesureyougiveyourapplicationthepermissiontoreadthecontacts.(UsesPermissions"android.permission.READ_CONTACTS"inAndroidManifest.xml)
18.AdditionalOpenSourcelibraries
SometimeshavingtopressarefreshbuttonontheActionBartorefreshdatacanbeannoyingfortheuser.ChrisBaneshasimplementedanOpenSourcelibrarytoimplementthepulltorefreshpatternforaListview.
4.ListActivity和ListFragment
4.1。使用ListView的默认容器
Android提供了专门的片段和活动课,以简化处理列表。该班是ListActivity类,如果你想使用列表中的活动和在
ListFragment,如果你想使用列表中的片段类。你不必布局分配给这些元素。如果你没有定义布局,活动或片段包含一个
ListView默认。
ListActivity和
ListFragment还允许您重写
onListItemClick()方法来处理选择列表中的项目。这两个类允许您设置适配器默认
ListView通过
setListAdapter()方法。下面的示例代码显示了一个简单的
ListFragment实现。接下来的示例代码演示的使用
ListActivity。
4.2。ListActivity和自定义布局
你可以使用一个自定义布局ListActivity或
ListFragment。在这种情况下,该片段或活性的搜索在为提供布局
ListView与预先定义
android:id属性设置为
@android:id/list。这种用法表现在下面的代码片段。
警告
如果你不使用这个ID或者不包括ListView到您的布局,一旦你尝试以显示活动或片段的应用程序崩溃。
4.3。占位符空列表
您还可以使用与视图@android:id/empty在布局ID。相应的活动和片段显示了这一观点自动如果
ListView是空的,否则隐藏它。例如,你可以在这样一个视图中显示错误消息。
5.练习:使用ListView和ListActivity
下面的练习演示如何使用ListView中的
ListActivity。可以使用预定义的
ArrayAdapter类和用于行现有机器人布局。创建一个名为de.vogella.android.listactivity与所谓的活动新的Android项目
MyListActivity。改变
MyListActivity基础上,下面的代码示例类。需要注意的是
setContentView()未使用的方法。
6.运动:ListActivity有自己的布局
在我们的例子中你将定义你的布局行,并用它在你的适配器。创建rowlayout.xml在布局文件
res/layout的文件夹
de.vogella.android.listactivity项目。所以在使用新的布局改变你的活动。
7.教程:实现自己的适配器
下面使用两个图像“no.png”和“ok.png”。我把它放在了“RES/绘制-MDPI”文件夹中。你必须创建自己的图标。如果你没有找到任何图标只是复制“的icon.png”,并使用绘图程序来改变它一点点。创建类MySimpleArrayAdapter这将作为我们的适配器。要使用此适配器,活动更改为以下。如果你运行这个例子,你应该得到不同的图标的某些元素的列表。
8.列表视图和性能
8.1。动机
性能在Android上尤其重要,因为用户所期望的快速的反应时间。与台式机相比Android设备是从硬件的角度来看相对缓慢。这部分介绍如何减少这些操作有效地实现您的自定义列表适配器。默认的Android适配器像ArrayAdapter已经优化性能。
8.2。耗时的操作
这从一个XML布局文件得到充气每个视图将导致Java对象。充气布局和创建Java对象是昂贵的问候时间和内存消耗。除了使用findViewById()方法比较费时,即使它不是那么糟糕,因为XML膨胀。
8.3。避免布局通胀和对象创建
一个ListView通常包含比显示的行数更多的数据。如果用户滚动列表中,则行和与其相关的意见正在滚动出可视区域的。它代表行的Java对象可以再次用于新的可见行。如果Android的确定一个行不再可见,它允许
getView()适配器方法重用通过相关视图
convertView参数。该适配器可以将新的数据包含在的视图层次的意见
convertView。这避免了膨胀的XML文件,并创建新的Java对象。在Android的情况下,不能再使用一排,Android系统传递
null到
convertView参数。因此适配器实现需要检查这一点。
8.4。查看持有人模式
一个ViewHolder实现允许避免findViewById()在适配器的方法。一
ViewHolder类通常是在你的适配器持有引用相关意见静态内部类。在您的布局。该参考分配给行视图,经由一个标签
setTag()方法。如果我们收到
convertView对象,我们可以得到的实例
ViewHolder通过
getTag()方法,并指定新的属性通过意见
ViewHolder参考。虽然这听起来复杂,这是更快的约15%,然后使用
findViewById()方法。
8.5。例
下面的代码显示了一个性能优化的适配器实现其重用现有的意见,并实现了持有人格局。9.保存视图的选择
默认情况下ListView没有选择模式激活。您可以通过激活它
setChoiceMode()方法调用。通过
ListView.CHOICE_MODE_MULTIPLE多个选择或
ListView.CHOICE_MODE_SINGLE单选择此方法。要获得的所选项目
ListView,使用
getCheckedItemPosition()为一个单一的选择方法或
listView.getCheckedItemPositions()进行多选。。如果你有稳定的ID,你也可以使用
getCheckedItemIds()方法来获得所选择的ID。安卓已经提供了这样的默认布局:在
android.R.layout.simple_list_item_multiple_choice布局,其中包含一个配置
CheckedTextView视图。以下活动演示了如何使用这些选择模式。如果你使用这些模式,
ListView存储选择的值。它不坚持你的数据模型。
10.上下文动作模式列表视图
以下假定您已经熟悉了动作条的一般概念和上下文的行动模式。这部分将介绍如何使用上下文的行动模式的ListView选择。要在单个项目分配上下文的动作模式,长按,使用的方法
setOnItemLongClickListener()上
ListView。该方法包括对所选项目的信息。在这种方法中,你可以开始
ActionMode。下面的实施例证明。它假定您已经定义了一个名为菜单XML文件
rowselection.xml而这个菜单包含一个条目与
@+id/menuitem1_showID。如果你启动应用程序,并长按列表中的一个项目,你会得到你的上下文行动吧。
11.实施撤消一个动作
11.1。当你要提供一个撤消操作?
这是很好的做法,以允许用户撤消关键行动。这样一个关键的动作是,例如,删除的列表项。甲证明图案来处理这种撤消选项是提供一种选择在屏幕的末端。后的预定时间该选择消失或者一旦用户继续与应用程序交互。例如,Gmail应用程序实现了这样的行为。11.2。例
下面的描述包含用于实现撤消操作的一个例子。它使用动画来自动淘汰撤销按钮了一段时间后。在这个例子中创建一个名为新项目com.vogella.android.userinterface.undo基础上,BlankTemplate模板。为您的布局如下活动。它使用的FrameLayout显示用户接口的两个不同的部分。按钮栏最初是隐藏的。按钮采用了绘制。无论是添加这样的绘制到项目或删除引用。
<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="match_parent"></ListView></RelativeLayout><LinearLayoutandroid:id="@+id/undobar"android:visibility="gone"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|center_horizontal"android:layout_margin="20dp"android:alpha="100"android:background="#808080"android:dividerPadding="11dp"android:padding="4dp"><TextViewandroid:id="@+id/undobar_message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Deleted"android:textAppearance="?android:attr/textAppearanceMedium"android:textColor="#fff"/><Buttonandroid:id="@+id/undobar_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="30dp"android:onClick="onClick"android:background="#808080"android:drawableLeft="@drawable/ic_undobar_undo"android:text="Undo"android:textAppearance="?android:attr/textAppearanceMedium"android:textColor="#fff"/></LinearLayout中></的FrameLayout>改变你的活动,使其类似于下面的代码。在Eclipse中的Android项目向导已经生成的
动作条条目。本条目中使用以下代码。如有疑问,创建自己的
动作条条目。如果您选择的入门动作条,按钮栏变为显示5秒钟。
12.性能优化
下面将实施适配器从前面的例子性能优化的版本。创建以下MyPerformanceArrayAdapter类。在您使用新的适配器的活动。如果你运行的应用程序应该看起来是一样的,但它会快很多,尤其是对于大型数据集。
13教程:如何显示在ListView两个项目
可以使用SimpleAdapter类显示两种元素的数据。此类期望字符串的一个阵列(
从数据),其中输入数据的字段定义。它还要求整数的数组定义为以这些字段映射行布局部件的ID。实际的数据是再映射的列表。地图定义了从数据的值的每个字段。以下示出了重用来自机器人的预定义布局的行的一个例子。
14.选择在ListView多个项目
14.1。模型和ListView互动
经常,你需要选择你的项目的ListView。由于排
的ListView越来越回收你不能存储在选择
视图的水平。
的ListView你定义自己的
适配器类。在这个适配器类附加一个监听到
视图负责选择模型元素。如果您选择更新,你可以作为一个标签添加到视图来访问它的模型的状态。下面的例子演示了如何使用标准的Java对象,如何从交互
视图和模型。
14.2。教程:域模型和交互行
继续使用de.vogella.android.listactivity项目。创建以下
模型如果该元素是当前选择哪个保持的名称和信息。创建一个名为以下新布局文件
rowbuttonlayout.xml。创建以下
适配器。此适配器加上了一个侦听器
复选框观点。如果该复选框被选中的模式的基础数据被改变。
复选框获取经由所分配的相应的模型元素
getTag()方法。最后,您更改活动以下内容。如果你开始你的应用程序,你应该能够标志的物品。这些变化将反映在您的模型。
15.实现可扩展的ListView
15.1。ExpandableListView
该ExpandableListView类似
的ListView但允许您定义组和详细信息该组。
ExpandableListView预期和类型的适配器
BaseExpandableListAdapter。在这种情况下,你必须定义两个布局,一个组,另一个用于详情一行。
15.2。ExpandableListView例如
在下面的例子中,你创建一个类似于下面的截图可扩展列表视图。MainActivity。创建或调整下列布局文件。一是
布局/activity_main.xml。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/LinearLayout1"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity"><ExpandableListViewandroid:id="@+id/listView"android:layout_width="match_parent"android:layout_height="wrap_content"></ExpandableListView></LinearLayout中>随后创建
布局/listrow_group.xml。
<CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="?android:attr/listPreferredItemHeight"android:layout_marginLeft="8dp"android:drawableRight="@drawable/ic_launcher"android:gravity="left"android:paddingLeft="32dp"android:paddingTop="8dp"android:text="Test"android:textSize="14sp"android:textAlignment="textEnd"android:textStyle="bold"/>最后所需的布局
布局/listrow_details.xml。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="40dp"android:clickable="true"android:orientation="vertical"android:paddingLeft="40dp"tools:context=".MainActivity"><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:drawableLeft="@drawable/ic_launcher"android:drawablePadding="5dp"android:gravity="center_vertical"android:text="@string/hello_world"android:textSize="14sp"android:textStyle="bold"></TextView><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="@android:color/black"/></LinearLayout中>创建占据着为你的域模型下面的类
ExpandableListView。最后创建适配器所描述的以下列表并改变活动下面提供的代码。
16.教程:杂项
16.1。添加longclick监听器列表项
您还可以添加LongItemClickListener的
视图。对于这个接收
的ListView经由
getListVIew()方法,并设置
LongItemClickListener经由setOnItemLongClickListener()方法。
16.2。页眉和页脚
当然,你可以把任意查看你周围的ListView元素。例如,你可以定义两个布局
TextViews和
ListView控件之间。在这种情况下,两个TextViews总是会名单(头)以上可见,另一个是下面的ListView可见。如果你只想在显示列表页眉或页脚列表中看到您可以使用该列表的开头或结尾
addHeaderView()方法或
addFooterView()上的方法
的ListView类。
17.SimpleCursorAdapter
如果你与内容供应商合作,或直接与数据库可以使用SimpleCursorAdapter定义数据为您
的ListView。下面将演示如何访问联系人ContentProvider的。创建一个名为“de.vogella.android.listactivity.cursor”与新的Android项目活动称为MyListActivity。改变
MyListActivity下面的内容。请确保你给你的应用程序读取联系人的权限。(在AndroidManifest.xml中使用权限“android.permission.READ_CONTACTS”)
18.其他开源库
有时不得不按下动作条的刷新按钮来刷新数据,可恼人的用户。克里斯·巴内斯实施了一个开放源码库来实现拉刷新模式的列表视图。https://github.com/chrisbanes/Android-PullToRefresh。你也可能需要使用的刷卡解雇的姿态,从一个ListView删除项目。罗马Nurik提供在一个这样的例子
相关文章推荐
- Using gdbserver and arm-eabi-gdb to debug native code in Android
- Using your own SQLite database in Android applications
- Using color in Android, by XML
- Using Flot's Bar Graph in an Android WebView with Highlighting
- Sencha Touch 2 官方文档翻译之 Using Views in your Applications(使用视图)
- 翻译:Picasa Style Photo Album Using ListView Control in ASP.Net 3.5
- Using your own SQLite database in Android applications
- using iscroll.js and iscroll jquery plugin in android webview to scroll div and ajax load data.
- Using SQLite in android demo
- Using JSON in Android
- 在Android程序里显示等待滚动圈(使用ProgressDialog)| Show waiting rolling circle in android application (using ProgressDialog)
- using Broadcast Receivers to listen outgoing call in android note
- Using custom attr in Android
- 【转载】Using SQLite from Shell in Android(在shell 下使用sqlite命令操作数据库)
- Android: How to download the latest zip Android Source Code easily and using it in Intellij
- Using SQLite from Shell in Android
- Android: Reading, using and working with XML data and web services in Android
- Using Google Maps in Android
- Using Android monkeyrunner from Eclipse in Windows
- Sencha Touch 2 官方文档翻译之 Using Views in your Applications(使用视图)