編輯:關於Android編程
/*
* Android開發之ExpandableListView
* 北京Android俱樂部群:167839253
* Created on: 2012-7-23
* Author: blueeagle
* Email:[email protected]
*/
有時候,使用ListView並不能滿足應用程序所需要的功能。有些應用程序需要多組ListView,這時候我們就要使用一種新的控件ExpandableListView——可以擴展的ListView。它的作用就是將ListView進行分組。就好像我們使用QQ的時候,有“我的好友”,“陌生人”,“黑名單”一樣,點擊一下會擴展開,再點擊一下又會收縮回去。
ExpandableListView是一個垂直滾動顯示兩級列表項的視圖,與ListView不同的是,它可以有兩層:每一層都能夠被獨立的展開並顯示其子項。這些子項來自於與該視圖關聯的ExpandableListAdapter。
每一個可以擴展的列表項的旁邊都有一個指示符(箭頭)用來說明該列表項目前的狀態(這些狀態一般是已經擴展開的列表項,還沒有擴展開的列表項,子列表項和最後一個子列表項)。可以使用方法:setChildIndicator(Drawable),setGroupIndicator(Drawable)(或者相應的XML文件的屬性) 去設置這些指示符的樣式。當然也可以使用默認的指示符。布android.R.layout.simple_expandable_list_item_1,android.R.layout.simple_expandable_list_item_2
和ListView一樣,ExpandableListView也是一個需要Adapter作為橋梁來取得數據的控件。一般適用於ExpandableListView的Adapter都要繼承BaseExpandableListAdapter這個類,並且必須重載getGroupView和getChildView這兩個最為重要的方法。
BaseExpandableListAdapter的主要重載方法如下:
public abstract ObjectgetChild (int groupPosition, int childPosition)
取得與指定分組、指定子項目關聯的數據.
參數
groupPosition 包含子視圖的分組的位置.
childPosition 指定的分組中的子視圖的位置.
返回
與子視圖關聯的數據.
public abstract long getChildId (int groupPosition, intchildPosition)
取得給定分組中給定子視圖的ID. 該組ID必須在組中是唯一的.必須不同於其他所有ID(分組及子項目的ID).
參數
groupPosition 包含子視圖的分組的位置.
childPosition 要取得ID的指定的分組中的子視圖的位置.
返回
與子視圖關聯的ID.
public abstract View getChildView (int groupPosition, intchildPosition, boolean isLastChild, View convertView, ViewGroup parent)
取得顯示給定分組給定子位置的數據用的視圖.
參數
groupPosition 包含要取得子視圖的分組位置.
childPosition 分組中子視圖(要返回的視圖)的位置.
isLastChild 該視圖是否為組中的最後一個視圖.
convertView 如果可能,重用舊的視圖對象.使用前你應該保證視圖對象為非空,並且是否是合適的類型.如果該對象不能轉換為可以正確顯示數據的視圖,該方法就創建新視圖.不保證使用先前由 getChildView(int, int,boolean, View, ViewGroup)創建的視圖.
parent 該視圖最終從屬的父視圖.
返回
指定位置相應的子視圖.
public abstract int getChildrenCount (int groupPosition)
取得指定分組的子元素數.
參數
groupPosition 要取得子元素個數的分組位置.
返回
指定分組的子元素個數.
public abstract long getCombinedChildId (long groupId, long childId)
取得一覽中可以唯一識別子條目的 ID(包括分組ID和子條目ID).可擴展列表要求每個條目 (分組條目和子條目)具有一個可以唯一識別列表中子條目和分組條目的ID. 該方法根據給定子條目ID和分組條目ID返回唯一識別ID.另外,如果 hasStableIds() 為真,該函數返回的ID必須是固定不變的.
參數
groupId 包含子條目ID的分組條目ID.
childId 子條目的ID.
返回
可以在所有分組條目和子條目中唯一識別該子條目的ID(可能是固定不變的).
public abstract long getCombinedGroupId (long groupId)
取得一覽中可以唯一識別子條目的 ID(包括分組ID和子條目ID).可擴展列表要求每個條目 (分組條目和子條目)具有一個可以唯一識別列表中子條目和分組條目的ID. 該方法根據給定子條目ID和分組條目ID返回唯一識別ID.另外,如果 hasStableIds() 為真,該函數返回的ID必須是固定不變的.
參數
groupId 分組條目ID.
返回
可以在所有分組條目和子條目中唯一識別該分組條目的ID(可能是固定不變的).
public abstract Object getGroup (int groupPosition)
取得與給定分組關聯的數據.
參數
groupPosition 分組的位置.
返回
指定分組的數據.
public abstract int getGroupCount ()
取得分組數.
返回
分組數.
public abstract long getGroupId (int groupPosition)
取得指定分組的ID.該組ID必須在組中是唯一的.必須不同於其他所有ID(分組及子項目的ID).
參數
groupPosition 要取得ID的分組位置.
返回
與分組關聯的ID.
public abstract View getGroupView (int groupPosition, booleanisExpanded, View convertView, ViewGroup parent)
取得用於顯示給定分組的視圖. 這個方法僅返回分組的視圖對象, 要想獲取子元素的視圖對象,就需要調用 getChildView(int, int, boolean, View, ViewGroup).
參數
groupPosition 決定返回哪個視圖的組位置 .
isExpanded 該組是展開狀態還是收起狀態 .
convertView 如果可能,重用舊的視圖對象.使用前你應該保證視圖對象為非空,並且是否是合適的類型.如果該對象不能轉換為可以正確顯示數據的視圖,該方法就創建新視圖.不保證使用先前由 getGroupView(int, boolean,View, ViewGroup)創建的視圖.
parent 該視圖最終從屬的父視圖.
返回
指定位置相應的組視圖.
public abstract boolean hasStableIds ()
是否指定分組視圖及其子視圖的ID對應的後台數據改變也會保持該ID.
返回
是否相同的ID總是指向同一個對象.
public abstract boolean isChildSelectable (int groupPosition, intchildPosition)
指定位置的子視圖是否可選擇.
參數
groupPosition 包含要取得子視圖的分組位置.
childPosition 分組中子視圖的位置.
返回
是否子視圖可選擇.
注意:
在XML布局文件中,如果ExpandableListView上一級視圖的大小沒有嚴格定義的話,則不能對ExpandableListView的android:layout_height 屬性使用wrap_content值。 (例如,如果上一級視圖是ScrollView的話,則不應該指定wrap_content的值,因為它可以是任意的長度。不過,如果ExpandableListView的上一級視圖有特定的大小的話,比如100像素,則可以使用wrap_content)
如果由於開發的時候粗心,對ExpandableListView指定wrap_content的值,則會報一個在SetContentView處的空指針錯誤。
根據描述,先看一個簡單的例子:
定義XML的代碼如下:
[html]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id = "@+id/myExpandableListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
</LinearLayout>
就是在LinearLayout中布置了一個ExpandableListView。
在JAVA中的代碼如下:
[java]
/*
* Android開發之ExpandableListView
* 北京Android俱樂部群:167839253
* Created on: 2012-7-23
* ExpandableListViewActivity.java
* Author: blueeagle
* Email: [email protected]
*/
package com.blueeagle.www;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
public class ExpandableListViewActivity extends Activity {
private List<String> GroupData;//定義組數據
private List<List<String>> ChildrenData;//定義組中的子數據
private void LoadListDate() {
GroupData = new ArrayList<String>();
GroupData.add("國家");
GroupData.add("人物");
GroupData.add("武器");
ChildrenData = new ArrayList<List<String>>();
List<String> Child1 = new ArrayList<String>();
Child1.add("蜀國");
Child1.add("魏國");
Child1.add("吳國");
ChildrenData.add(Child1);
List<String> Child2 = new ArrayList<String>();
Child2.add("關羽");
Child2.add("張飛");
Child2.add("典韋");
Child2.add("呂布");
Child2.add("曹操");
Child2.add("甘寧");
Child2.add("郭嘉");
Child2.add("周瑜");
ChildrenData.add(Child2);
List<String> Child3 = new ArrayList<String>();
Child3.add("青龍偃月刀");
Child3.add("丈八蛇矛槍");
Child3.add("青鋼劍");
Child3.add("麒麟弓");
Child3.add("銀月槍");
ChildrenData.add(Child3);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LoadListDate();
ExpandableListView myExpandableListView = (ExpandableListView)findViewById(R.id.myExpandableListView);
myExpandableListView.setAdapter(new ExpandableAdapter());
}
private class ExpandableAdapter extends BaseExpandableListAdapter {
@Override
public Object getChild(int groupPosition, int childPosition) {
return ChildrenData.get(groupPosition).get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
TextView myText = null;
if (convertView != null) {
myText = (TextView)convertView;
myText.setText(ChildrenData.get(groupPosition).get(childPosition));
} else {
myText = createView(ChildrenData.get(groupPosition).get(childPosition));
}
return myText;
}
@Override
public int getChildrenCount(int groupPosition) {
return ChildrenData.get(groupPosition).size();
}
@Override
public Object getGroup(int groupPosition) {
return GroupData.get(groupPosition);
}
@Override
public int getGroupCount() {
return GroupData.size();
}
@Override
public long getGroupId(int groupPosition) {
return 0;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
TextView myText = null;
if (convertView != null) {
myText = (TextView)convertView;
myText.setText(GroupData.get(groupPosition));
} else {
myText = createView(GroupData.get(groupPosition));
}
return myText;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
private TextView createView(String content) {
AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 80);
TextView myText = new TextView(ExpandableListViewActivity.this);
myText.setLayoutParams(layoutParams);
myText.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
myText.setPadding(80, 0, 0, 0);
myText.setText(content);
return myText;
}
}
}
效果如下圖所示:
這樣就完成了一個最簡單的ExpandableListView的控件。
在實際開發過程中,常常有不同的需求,比如每一個child需要不同的控件,每一個group或者child需要有圖標,圖標顯示需要不一樣,需要設置背景等各種各樣能夠讓我們的程序變得美觀的需求。那麼下面就逐一討論一下ExpandableListView如何實現這些需求。
比如,為ExpandableListView設置背景,並且默認展開第n組,n從0開始計數,則只需要添加如下代碼:
[java]
myExpandableListView.setBackgroundResource(R.drawable.background);
myExpandableListView.expandGroup(0);
則效果如下:
改變每個組前面的圖標,並且圖標樣式隨著合攏和展開不同,則只需要在res/drawable目錄下定義文件:Indicator.xml
[html]
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_expanded="true" android:drawable="@drawable/right" />
<item android:drawable="@drawable/down"></item>
</selector>
在JAVA文件中添加:
[java]
myExpandableListView.setGroupIndicator(this.getResources().getDrawable(R.drawable.indicator));
效果如下:
對於其他的屬性設置,可以參考以下屬性說明:
android:childDivider
來分離子列表項的圖片或者是顏色。注:圖片不會完全顯示,分離子列表項的是一條直線
android:childIndicator
在子列表項旁邊顯示的指示符。注:可以是一個圖片
android:childIndicatorLeft
子列表項指示符的左邊約束位置。注:即從左端0位置開始計數,比如,假設指示符是一個圖標,給定這個屬性值為3dip,則表示從左端起3dip開始顯示此圖標。
android:childIndicatorRight
子列表項指示符的右邊約束位置。注:表示右端到什麼位置結束
android:groupIndicator
在組列表項旁邊顯示的指示符。注:可以是一個圖片。
android:indicatorLeft
組列表項指示器的左邊約束位置。注:表示左端從什麼位置開始。
android:indicatorRight
組列表項指示器的右邊約束位置。注:表示右端到什麼位置結束。
當然,還可以使用自定義的View去描述group和child,自定義的View可以和布局文件一樣,寫在layout文件夾下。例如命名為group.xml或者child.xml。
例如,我們定義一個child項由一個ImageView和一個TextView來組成,則可以定義child.xml為:
[html]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation = "horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_gravity = "center_vertical"
android:id = "@+id/imageView01"
android:layout_width = "70px"
android:layout_height = "70px"
android:paddingLeft = "30px"
android:paddingTop = "2px"
android:paddingBottom = "5px"
android:src = "@drawable/ic_launcher"/>
<TextView
android:layout_gravity = "center_vertical"
android:id = "@+id/childTV"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:paddingLeft = "30px"
android:paddingTop = "10px"
android:paddingBottom = "5px"
android:textSize = "30sp"/>
</LinearLayout>
對於其中的屬性不再做詳細說明。
對於ExpandableListView中的數據,還可以用以下方式定義:
[java]
List<Map<String, String>> groups = new ArrayList<Map<String, String>>();
Map<String, String> group1 = new HashMap<String, String>();
group1.put("group", "國家");
… …
groups.add(group1);
… …
//准備第一個一級列表中的二級列表數據:三個二級列表,分別顯示"魏國"、"蜀國"和"吳國"
List<Map<String, String>> child1 = new ArrayList<Map<String, String>>();
Map<String, String> child1Data1 = new HashMap<String, String>();
child1Data1.put("child", "魏國");
… …
child1.add(child1Data1);
… …
//准備第二個一級列表中的二級列表數據:八個二級列表,顯示"關羽"、"張飛"、"典韋"、"呂布"、"曹操"、"甘寧"、"郭嘉"、"周瑜"
List<Map<String, String>> child2 = new ArrayList<Map<String, String>>();
Map<String, String> child2Data1 = new HashMap<String, String>();
child2Data1.put("child", "關羽");
… …
child2.add(child2Data1);
… …
//准備第三個一級列表中的二級列表數據:五個二級列表,顯示 "青龍偃月刀"、"丈八蛇矛槍"、 "青鋼劍"、"麒麟弓"、"銀月槍"
List<Map<String, String>> child3 = new ArrayList<Map<String, String>>();
Map<String, String> child3Data1 = new HashMap<String, String>();
child3Data1.put("child", "青龍偃月刀");
… …
child3.add(child3Data1);
… …
//用一個list對象保存所有的二級列表數據
List<List<Map<String, String>>> childs = new ArrayList<List<Map<String, String>>>();
childs.add(child1);
childs.add(child2);
childs.add(child3);
針對上述數據定義方式,修改java文件:
例如:在getChildView函數中做如下編寫,
String text = groups.get(groupPosition).get("group");
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//獲取一級列表布局文件,設置相應元素屬性
LinearLayout linearLayout = (LinearLayout) layoutInflater.inflate(R.layout.group, null);
TextView textView = (TextView)linearLayout.findViewById(R.id.textView01);
textView.setText(text);
return linearLayout;
這樣就可以將自定義的View寫入到child中,當然,這裡也可以不用布局文件來定義View,也可以自己用代碼實現View。
補充知識:
對於ExpandableListView相應的,也有一個ExpandableListActivity與之對應,對於只需要一個ExpandableListView的Activity,則只需要使用ExpandableListActivity來完成相應的功能就可以了。但是需要注意一點的是:在main.xml頁面中添加如下代碼: www.2cto.com
[html]
<ListView android:id="@android:id/list" 或android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</ListView>
作者:redoffice
在android的應用層中,涉及到很多應用框架,例如:Service框架,Activity管理機制,Broadcast機制,對話框框架,標題欄框架,狀態欄框架,通知機制,
前言通過“計算器”應用我們已經熟悉了安卓應用開發的大致流程,具備了開發的初步知識。接下來,我們將開始制作一個“視頻播放器”
我們的手機通訊錄一般都有這樣的效果,如下圖:OK,這種效果大家都見得多了,基本上所有的android手機通訊錄都有這樣的效果。那我們今天就來看看這個效果該怎麼實現。一.概
ADT插件:管理Android SDK和相關的開發工具的NDK插件:用於開發Android NDK的插件,ADT版本在20以上,就能安裝NDK插件,另外NDK集成了CDT