expand
[Android]界面的布局-ExpandableListView
http://ysl-paradise.blogspot.com/2011/05/listview-ii.html
1.可展开的ListView
在這一篇中,我們來看看如何自定义一个两层结构的ListView。如下图所示:
[Android]界面的布局-ExpandableListView
当点击PeopleNames,就显示对应的子列表,如下图:
[Android]界面的布局-ExpandableListView
如何可以做到上面的效果呢?首先我们自定义一个MyExpandableListAdapter.它继承自BaseExpandableListAdpter.
publicclassMyExpandableListAdapterextendsBaseExpandableListAdapter{
//Sampledataset.children[i]containsthechildren(String[])forgroups[i].
privateString[]groups={"PeopleNames","DogNames","CatNames","FishNames"};
privateString[][]children={
{"Arnold","Barry","Chuck","David"},
{"Ace","Bandit","Cha-Cha","Deuce"},
{"Fluffy","Snuggles"},
{"Goldy","Bubbles"}
};
publicObjectgetChild(intgroupPosition,intchildPosition){
returnchildren[groupPosition][childPosition];
}
publiclonggetChildId(intgroupPosition,intchildPosition){
returnchildPosition;
}
publicintgetChildrenCount(intgroupPosition){
returnchildren[groupPosition].length;
}
publicTextViewgetGenericView(){
//LayoutparametersfortheExpandableListView
AbsListView.LayoutParamslp=newAbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,64);
TextViewtextView=newTextView(TestExpandableListActivity.this);
textView.setLayoutParams(lp);
//Centerthetextvertically
textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
//Setthetextstartingposition
textView.setPadding(60,0,0,0);//第一层的textview,距离上下左右边界的距离。
returntextView;
}
publicViewgetChildView(intgroupPosition,intchildPosition,booleanisLastChild,
ViewconvertView,ViewGroupparent){
TextViewtextView=getGenericView();
textView.setText(getChild(groupPosition,childPosition).toString());
returntextView;
}
publicObjectgetGroup(intgroupPosition){
returngroups[groupPosition];
}
publicintgetGroupCount(){
returngroups.length;
}
publiclonggetGroupId(intgroupPosition){
returngroupPosition;
}
publicViewgetGroupView(intgroupPosition,booleanisExpanded,ViewconvertView,
ViewGroupparent){
TextViewtextView=getGenericView();
textView.setText(getGroup(groupPosition).toString());
returntextView;
}
publicbooleanisChildSelectable(intgroupPosition,intchildPosition){
Toast.makeText(TestExpandableListActivity.this,getChild(groupPosition,childPosition).toString(),Toast.LENGTH_LONG).show();
returntrue;
}
publicbooleanhasStableIds(){
returntrue;
}
}
接着,新建一个工程,在主Activity里加入下面代码:
publicclassTestExpandableListActivityextendsExpandableListActivity{
ExpandableListAdaptermAdapter;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
//setupouradapter
mAdapter=newMyExpandableListAdapter();
setListAdapter(mAdapter);
registerForContextMenu(getExpandableListView());
}
}
上面的源代码在你本机c:\ProgramFiles\Android\android-sdk\samples\android-10_1\ApiDemos\src\com\example\android\apis\view\ExpandableList1.java
里可以找到。
2.自定义ExpandableListView的显示
上面的可展开的ListView黑乎乎的,且间隔很大。如何修改它的Layout呢?
2.1修改父界面。效果如下图:
[Android]界面的布局-ExpandableListView
新建一个xml文件,用来显示父界面。xml内容如下:
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"android:orientation="horizontal"
android:layout_height="wrap_content"android:background="#ccc"
android:gravity="left|center_vertical"android:minheight="40dip"
android:paddingRight="20dip"android:paddingLeft="10dip">
<TextViewandroid:id="@+id/txtGroupName"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"
android:textSize="20dip"
android:textColor="#000"
android:paddingLeft="3dip"
android:singleLine="true"/>
</LinearLayout>
其实只有一个textview控件,用来显示A,B,C,D。。。左边的展开折叠按钮时系统提供的。现在就先不修改它了。
用这个xml文件,主要是想设置奇偶行的颜色,这样使用起来比较清楚。不然背景是黑乎乎一片,使用起来不是那么舒服。
源代码里只需要修改一个函数。如下:
publicViewgetGroupView(intgroupPosition,booleanisExpanded,
ViewconvertView,ViewGroupparent){
StringstrGroup=mCategoryList.get(groupPosition);//自己取得要显示内容。mCategoryList其实就是一个List<String>里面存放了26个字母而已。
//设置Layout
LayoutInflaterinflater=(LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayoutll=(LinearLayout)inflater.inflate(R.layout.artistlist_group,null);
TextViewtv=(TextView)ll.findViewById(R.id.txtGroupName);
tv.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
//设置字符开始的位置,如果不够大的话,字符就和左边的展开/折叠图标重叠了。自己可以改改数字,看看效果就明白了。
tv.setPadding(60,0,0,0);
//设置显示的内容
tv.setText(strGroup);
//设置奇偶行的背景交错
ll.setBackgroundColor(groupPosition%2==0?Color.argb(250,255,255,255):Color.argb(250,229,229,229));
returnll;
}
2.2修改展开后的子界面。效果如下图:
[Android]界面的布局-ExpandableListView
其实和上面未展开前的父界面差不多,是不是?
新建一个xml文件,用来显示子界面。
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"android:orientation="horizontal"
android:layout_height="wrap_content"android:background="#fff"
android:gravity="left|center_vertical"android:minheight="40dip"
android:paddingRight="20dip"android:paddingLeft="10dip">
<TextViewandroid:id="@+id/txtArtistName"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"
android:textSize="16dip"
android:textColor="#000"
android:paddingLeft="3dip"
android:singleLine="true"/>
<ImageViewandroid:id="@+id/imgArtist"
android:src="@drawable/arrow_right_rest"
android:paddingRight="5dip"
android:layout_width="24dip"
android:layout_height="24dip"
android:contentDescription="@string/artist"/>
</LinearLayout>
从上面可以看出,textview用来显示文字,图片就是右边的那个箭头符号。
源代码如下:
publicViewgetChildView(intgroupPosition,intchildPosition,
booleanisLastChild,ViewconvertView,ViewGroupparent){
//取得要展开的子条目的内容
StringstrArtistName=mArtistList.get(groupPosition).get(childPosition);//mArtistList其实就是一个List<List<String>>
//设置界面
LayoutInflaterinflater=(LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayoutll=(LinearLayout)inflater.inflate(R.layout.artistlist_row,null);
TextViewtv=(TextView)ll.findViewById(R.id.txtArtistName);
//设置内容
tv.setText((childPosition+1)+"."+strArtistName);
//设置奇偶行。因为父界面也是奇偶行分割的,为了和父条目的颜色呼应,所以这里要判断一下父条目的颜色。
//即父条目为灰色,那么第一个子条目应该是白色。如果两个都是灰色,就连成一片了。
if(groupPosition%2==0)
ll.setBackgroundColor(childPosition%2==0?Color.argb(250,229,229,229):Color.argb(250,255,255,255));
else
ll.setBackgroundColor(childPosition%2==0?Color.argb(250,255,255,255):Color.argb(250,229,229,229));
returnll;
}
这样就完成了自定义展开前和展开后的效果了。
3.点击某个父条目时,如何收起其他已经展开的条目?
当我们点击某个父条目时,如果这个条目本身是没有展开的,我们需要做两个动作:
1.折叠其他已经展开的条目(为什么?实际应用中需要。不需要的话可以忽略此步)
2.展开这个条目
然而在实现过程中,总是出现异常。
03-1517:18:13.090:ERROR/AndroidRuntime(16202):FATALEXCEPTION:main
03-1517:18:13.090:ERROR/AndroidRuntime(16202):java.lang.IndexOutOfBoundsException:Invalidindex1,sizeis0
真是头晕啊。不知道哪里越界了呢?怎么会size为0呢?跟了好久都不知道为何。看了这篇博文,http://qtcstation.com/2011/03/working-with-the-expandablelistview-part-1/
终于明白了。我也是将折叠其他条目写在onGroupClicl里了.改写在onGroupExpand就没事了。唉唉。
privateExpandableListView.OnGroupExpandListenermGroupExpandListener=newExpandableListView.OnGroupExpandListener(){
publicvoidonGroupExpand(intgroupPosition){
intlen=mAdapter.getGroupCount();
for(inti=0;i<len;i++)
if(i!=groupPosition)
mExpandListView.collapseGroup(i);
}
};
privateExpandableListView.OnGroupClickListenermGroupClickListener=newExpandableListView.OnGroupClickListener(){
publicbooleanonGroupClick(ExpandableListViewparent,Viewv,
intgroupPosition,longid){
//collapseAllExpanded();就是在这里折叠条目出错了。千万不能写在这里。写到onGroupExpand里。
startSearch(groupPosition);//自己写的动态从网上搜索要显示的子条目。改成自己的函数即可。
returnfalse;
}
};
4.旋转时如何让展开的条目保持展开状态并显示它的子条目?
当我们由横屏转竖屏,或竖屏转横屏时,App会有个重新初始化的过程。这时候不做任何处理的话,展开的条目就会丢失它的子条目。这样的显示效果显然是不友好的。旋转后如何保持刚才的内容呢?
下面这篇文章非常有用。
http://stackoverflow.com/questions/4184556/save-and-restore-expanded-collapsed-state-of-an-expandablelistactivity
我们需要用一个数组来记住已经展开的group的id。在onSaveInstanceState函数中记住展开的id。在onRestoreInstanceState函数中恢复这些id,将它们展开。
还要在onStart中检查是否有展开的id,如果有的话,展开这些id。
在onStop中记得储存这些展开的id。
privatelong[]mExpandedIds;//saveexpandedgroupid
@Override
protectedvoidonStart(){
super.onStart();
if(this.mExpandedIds!=null)
restoreExpandedState(mExpandedIds);
}
@Override
protectedvoidonStop(){
super.onStop();
mExpandedIds=getExpandedIds();
}
@Override
protectedvoidonSaveInstanceState(BundleoutState)
{
super.onSaveInstanceState(outState);
this.mExpandedIds=getExpandedIds();
outState.putLongArray("ExpandedIds",this.mExpandedIds);
}
@Override
protectedvoidonRestoreInstanceState(BundlesavedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
long[]expandedIds=savedInstanceState.getLongArray("ExpandedIds");
if(expandedIds!=null)
restoreExpandedState(expandedIds);
}
//取得所有展开的group的id
privatelong[]getExpandedIds(){
if(mAdapter!=null)
{
intlength=mAdapter.getGroupCount();
ArrayList<Long>expandedIds=newArrayList<Long>();
for(inti=0;i<length;i++)
{
//判断这个group是否展开。如果展开,就记下来
if(mExpandListView.isGroupExpanded(i))
{
expandedIds.add(mAdapter.getGroupId(i));
}
}
returntoLongArray(expandedIds);
}
else
returnnull;
}
//恢复到展开状态
privatevoidrestoreExpandedState(long[]expandedIds)
{
this.mExpandedIds=expandedIds;
if(mExpandedIds!=null)
{
if(mAdapter!=null)
{
for(inti=0;i<mAdapter.getGroupCount();i++)
{
longid=mAdapter.getGroupId(i);
if(inArray(expandedIds,id))
{
startSearch((int)id);//自己写的动态寻找对应的子条目的函数。改成自己的函数即可。
//如果这个group已经是展开的,那么折叠它,再展开。否则显示的子条目内容在旋转前后不一样。
if(!mExpandListView.expandGroup((int)id))
{
mExpandListView.collapseGroup((int)id);
mExpandListView.expandGroup((int)id);
}
}
}
}
}
}
privatestaticbooleaninArray(long[]array,longelement){
for(longl:array){
if(l==element){
returntrue;
}
}
returnfalse;
}
privatestaticlong[]toLongArray(List<Long>list){
long[]ret=newlong[list.size()];
inti=0;
for(Longe:list)
ret[i++]=e.longValue();
returnret;
}
相关推荐
相对布局只要是要有参照物,即谁在谁下方,谁在谁左边,和谁左对齐,等等。然后再添加一个按钮使其在textView的下方以及在立即更新按钮的左边。android:text="发现新的版本,您想现在更新吗?