Android常用列表控件
列表控件用於顯示數據集合,Android不是使用一種類型的控件管理顯示和數據,而是將這兩項功能分佈用列表控件和適配器來實現。列表控件擴展了android.widget.AdapterView的類,包括ListView、GridView、Spinner和Gallery。
1)基本的列表控件ListView
ListView控件垂直顯示一組項,通常通過編寫一個擴展android.app.ListActivity的新活動來使用ListView。ListActivity包含一個ListView,可以調用setListAdapter()方法來爲ListView設置數據。前面介紹過適配器將列表控件鏈接到數據,幫助爲列表控件準備子視圖,可單擊ListView中的某一項來立即執行操作,或選擇它們以稍後對所選擇項集合採取操作。
Demo1:
<LinearLayout xmlns: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"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</ListView>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="Submit Selection" >
</Button>
</LinearLayout>
我們通過改寫系統的提供的佈局android.R.layout.list,向其中添加一個Button。注意:這裏ListView的ID的規範:必須使用@android:id/list,因爲ListActivity需要在佈局中找到一個R.layout.list的ListView。
其次還需要注意的是:在佈局LinearLayout中指定的ListView的高度,我們希望Button永遠顯示在在屏幕上,無論ListView中有多少項,我們不希望滾動到頁面底部才能看到按鈕。所以這裏ListView的layout_height設置爲0,然後使用layout_weight表面此空間應該佔據父容器中的所有可用空間,同時爲Button預留了空間。
最後我們未Button按鈕添加了一個響應函數doClick。所以在我們的MainActivity中需要實現doClick方法。
代碼清單:
public class MainActivity extends ListActivity {
private ListView lv = null;
private Cursor cursor;
private int idCol = -1;
private int nameCol = -1;
private int noteCol = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list);
lv = getListView();
cursor = managedQuery(People.CONTENT_URI, null, null, null, People.NAME);
String cols[] = new String[] {People.NAME};
int [] views = new int[] {android.R.id.text1};
idCol = cursor.getColumnIndex(People._ID);
nameCol = cursor.getColumnIndex(People.NAME);
noteCol = cursor.getColumnIndex(People.NOTES);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_multiple_choice,
cursor, cols, views);
this.setListAdapter(adapter);
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
public void doClick(View view) {
int count = lv.getCount();
SparseBooleanArray viewItems = lv.getCheckedItemPositions();
for(int i = 0; i < count; i++) {
if(viewItems.get(i)) {
cursor.moveToPosition(i);
long id = cursor.getLong(idCol);
String name = cursor.getString(nameCol);
String notes = cursor.getString(noteCol);
Toast.makeText(this, "info: id="+id+" name="+name+" notes="+notes, Toast.LENGTH_LONG).show();
}
}
}
}
代碼中:我們首先調用setContentView()方法設置活動的用戶界面,在適配器的設置中我們爲ListView的每一行傳遞了Android所提供了另一個視圖android.R.layout.simple_list_item_multiple_choice,這將導致導致每一行擁有一個TextView與一個CheckBox。通過查看這個佈局文件,將會看到其實是CheckedTextView,繼承於TextView,這個特殊的TextView專門用於ListView的。它的TextView的ID爲android.R.id.text1。
爲了讓用戶能夠選擇多行,我們設置了ListView.CHOICE_MODE_MULTIPLE屬性。
最後爲了實現用於提交功能我們添加了一個Button,併爲其添加了響應方法doClick。在doClick()方法中我們調用ListView.getCheckedItemPositions()返回一個boolean類型數組,表面是否選擇了某一項。然後我們迭代ListView所有項,如果選擇了相應行,viewItems.get(i)將返回true。當從ListView獲得已經選擇的位置編號之後我們就可以使用Cursor的moveToPosition()移動到相應位置讀取數據了。
2)網格控件GridView
Android有一個GridView控件可通過網格的形式顯示信息。GridView的使用模式是首先在佈局文件中定義網格,然後使用android.widget.ListAdapter將數據綁定到網格。下面我們同樣以顯示聯繫人爲Demo,只不過這次是以網格的形式顯示出來:
<GridView xmlns: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"
android:id="@+id/grid"
android:padding="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:numColumns="auto_fit"
android:columnWidth="100dp"
android:stretchMode="columnWidth"
android:gravity="center">
</GridView>
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gv = (GridView)this.findViewById(R.id.grid);
Cursor cursor = managedQuery(ContactsContract.Contacts.CONTENT_URI, null, null, null, ContactsContract.Contacts.DISPLAY_NAME);
String cols[] = new String[] {ContactsContract.Contacts.DISPLAY_NAME};
int [] views = new int[] {android.R.id.text1};
int idCol = cursor.getColumnIndex(ContactsContract.Contacts._ID);
int nameCol = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
int noteCol = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_SOURCE);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1,
cursor, cols, views);
gv.setAdapter(adapter);
}
}
網格顯示了設備上聯繫人的姓名。代碼中MainActivity擴充了Activity,而不是ListActivity,然後使用setContentView()來設置GridView的佈局,最後爲了設置適配器,我們調用了GridView的setAdapter()方法。注意:網格使用的適配器是ListAdapter,由於列表是一維的,而網格是二維的,所以網格實際上顯示了面向列表的數據。
3)下拉框控件Spinner
Spinner就像一個下拉菜單,通常用於從相對較短的選擇列表中進行選擇,如果選擇列表太長,會自動添加一個滾動條。我們可以通過XML佈局簡單實例化Spinner。
<Spinner
android:id="@+id/spinner"
android:prompt="@string/spinnerPrompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
下拉框控件在靜止時顯示一個值,當用戶單擊小箭頭時,顯示一個列表提供給用戶選擇一個新值。填充此列表的方式和填充其他列表控件的方式相同,都是使用適配器。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
Spinner spinner = (Spinner)this.findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="planets">
<item>Monday</item>
<item>Tuesday</item>
<item>Wednesday</item>
<item>Thursday</item>
<item>Friday</item>
<item>Saturday</item>
<item>Sunday</item>
</string-array>
</resources>
代碼中首先通過setContentView來設置當前佈局,然後找到相應的Spinner。通過ArrayAdapter.createFromResource()定義了微調框在正常模式下的外觀,然後使用adapter.setDropDownViewResource()設置彈出列表模式的微調框。
4)水平滾動的列表控件Gallery
Gallery控件是一種可水平滾動的列表控件,焦點始終位於列表中央,此控件通常在觸摸屏模式下用在相冊,既可以通過XML佈局也可以通過代碼實例化Gallery。
<Gallery
android:id="@+id/gallery"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
Gallery控件通常用於顯示圖像,所以適配器可能會針對圖像特殊化,爲此Android提供了一個名爲BaseAdapter的抽象類,我們通過擴展它,自定義適配器。
Demo:
<GridView xmlns: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"
android:id="@+id/gridView"
android:padding="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:numColumns="auto_fit"
android:gravity="center">
</GridView>
activity_main.xml中有一個主要佈局,其中包含了一個GridView定義,我們需要從該佈局獲取GridView的引用。然後實例化一個MyAdapter,繼承於BaseAdapter。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gv = (GridView)this.findViewById(R.id.gridView);
MyAdapter adapter = new MyAdapter(this);
gv.setAdapter(adapter);
}
public class MyAdapter extends BaseAdapter {
private int convertViewCounter = 0;
private Context context;
private LayoutInflater inflater;
private int imgId[] = {R.drawable.img1, R.drawable.img2, R.drawable.img3,
R.drawable.img4, R.drawable.img5, R.drawable.img6};
private Bitmap[] images = new Bitmap[imgId.length];
private Bitmap[] Thumbs = new Bitmap[imgId.length];
class ViewHolder {
ImageView image;
}
public MyAdapter(Context context) {
// TODO Auto-generated constructor stub
this.context = context;
inflater = LayoutInflater.from(context);
for(int i = 0; i < imgId.length; i++) {
images[i] = BitmapFactory.decodeResource(context.getResources(), imgId[i]);
Thumbs[i] = Bitmap.createScaledBitmap(images[i], 100, 100, false);
}
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return imgId.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return images[position];
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.gridimage, null);
convertViewCounter++;
holder = new ViewHolder();
holder.image = (ImageView)convertView.findViewById(R.id.gridImageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.image.setImageBitmap(Thumbs[position]);
return convertView;
}
}
}