本講的核心是向大家介紹如何通過自定義適配器來應用到ListView和GridView上,並介紹ListView和GridView的常用方法。
作爲最常使用的兩種控件,ListView 和GridView廣泛出現在各種APP中,最常見的就是電話薄和九宮格,Android自身也提供了相應的適配器比如SimpleAdapter,但往往我們在開發過程中對於列表項有更高的要求,此時SimpleAdapter便不能勝任了,同時SimpleAdapter的書寫過於繁瑣,對比一下就知道:
// 使用simpleAdapter封裝數據,將圖片顯示出來,此時的適配器沒有監聽功能
// 參數一是當前上下文Context對象
// 參數二是圖片數據列表,要顯示數據都在其中
// 參數三是界面的XML文件,注意,不是整體界面,而是要顯示在GridView中的單個Item的界面XML
// 參數四是動態數組中與map中圖片對應的項,也就是map中存儲進去的相對應於圖片value的key
// 參數五是單個Item界面XML中的圖片ID
SimpleAdapter simpleAdapter = new SimpleAdapter(this, imagelist, R.layout.items, new String[] { "image", "text" }, new int[] {R.id.image, R.id.title });
gridview.setAdapter(simpleAdapter);
// 使用自定義的DownAdapter封裝數據,此時的適配器有監聽功能
// 參數一是當前上下文Context對象
// 參數二是列表項數據列表,一個列表項要顯示的數據都在其中
// 參數三是當前要使用該適配器的視圖
DownAdapter downadapter = new DownAdapter(this,list,girdview);
gridview.setAdapter(downadapter);
怎麼樣,差距是不是很明顯,沒有人喜歡這麼長的輸入方式,除非你是女的。
好了,不說廢話了,下面就是我們今天用到的代碼,具體的解釋都寫在裏面了,有疑問的可以留言。
首先我們西安家裏兩個包,分別分裝ListView和GirdView的項目格式。這個格式隨你而變。
相應的我們重建一下第一講中的view_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- @author Arthur Lee -->
<!-- 垂直分佈兩個,以AB標記 -->
<!-- A -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"
android:gravity="center_vertical|center_horizontal">
<TextView
android:id="@+id/view_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一頁面"
android:textSize="20sp" />
</LinearLayout>
<!-- A -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<!-- 水平分佈兩個,一12標記 -->
<!-- 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4">
<!-- 提示欄 -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="上欄是ListView,下欄是GridView"
android:textSize="20sp"/>
</LinearLayout>
<!-- 2 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<!-- 垂直分佈兩個,以ab標記 -->
<!-- a -->
<LinearLayout
android:id="@+id/firist_upview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- ListView展示區 -->
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/first_up"></ListView>
</LinearLayout>
<!-- b -->
<LinearLayout
android:id="@+id/firist_downview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- GridView展示區 -->
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/first_down"
android:horizontalSpacing="5dp"
android:verticalSpacing="5dp"
android:stretchMode="columnWidth"
android:columnWidth="90dp"
android:numColumns="4" ></GridView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
//Up是一個角色類,也可以把它寫成一個內部類,用它來封裝列表項的數據,既方便有美觀。
public class Up {
//自定義的參數
private String strName;
private String strNum;
public Up(String strName, String strNum) {
super();
this.strName = strName;
this.strNum = strNum;
}
//我們需要爲這個角色類設置get和set方法,以便於獲取和傳遞數據
public String getStrName() {
return strName;
}
public void setStrName(String strName) {
this.strName = strName;
}
public String getStrNum() {
return strNum;
}
public void setStrNum(String strNum) {
this.strNum = strNum;
}
}
package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.ArrayList;
import java.util.List;
public class UpSerivce {
/**
* 在這個服務類裏,我只定義了一個getString方法來獲得列表項數據,大家可以在這裏對數據進行封裝處理。
* 盡你所能,我在這裏就偷懶了,大家不要學我啊,
* by the way,這個服務類可有可無,我這樣單獨建一個類主要是爲了方便大家學習。只要有getString這個方法就行
* @param 這裏的參數可以是任何形式,對於客戶端的開發來說,最常用的就是JSON格式。這個我會在第七講中詳細介紹JSON格式
* @return 直接返回我們封裝好的數據隊列
*/
public static List<Up> getString(int count){
List<Up> up = new ArrayList<Up>();
for(int i=0;i<count;i++)
up.add(new Up("觀衆"+i+"號","按鍵"+i+"號"));
return up;
}
}
package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.List;
import com.teach.demo.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class UpAdapter extends BaseAdapter{
private Context context;
private LayoutInflater inflater;
private List<Up> first;
private ListView list;
//設定列表項所需控件,要和自己設計 的列表項控件一致。
//在這裏我偷懶一下,就放三個。
static class ListItem{
TextView tView;
ImageView iView;
Button bt_click;
Button bt_delect;
}
/**設置構造函數,對pUAdapter的內容進行綁定
* @param context 決定當前Actvity類
* @param first 所需加載啊的列表項數據
* @param list 當前適配器匹配的視圖類型,這裏換成GridView類型的話,顯示的列表項就會是九宮格風格
*/
public UpAdapter(Context context,List<Up> first,ListView list){
this.context = context;
//指定當前LayoutInflater服務的Activity,一遍後面初始化相應的視圖。
this.inflater = LayoutInflater.from(context);
this.list = list;
this.first = first;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return first.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return first.get(position);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
/**
* @param position 指定列表項的當前所處位置
* @param view 指定視圖,即當前列表項
* @param parents 指定視圖所屬的父類,即當前列表項所屬的列表
*
* 此處是Adapter的關鍵所在,任何視圖在配置Adapter時,
* 都是通過調用Adapter的getView方法,將視圖中所需的每個小項組裝成定義後的樣子。
*/
@Override
public View getView(final int position, View view, ViewGroup parents) {
// TODO Auto-generated method stub
ListItem item = null;
//如果當前爲空,則對視圖進行初始化
if(view == null){
//指定當前視圖所對應xml文件。並初始化其中的控件,這個view就是一個小的列表項
view = inflater.inflate(R.layout.view_first_upitem, null);
item = new ListItem();
item.iView = (ImageView)view.findViewById(R.id.first_photo);
item.bt_click = (Button)view.findViewById(R.id.first_click);
item.bt_delect = (Button)view.findViewById(R.id.first_delect);
item.tView = (TextView)view.findViewById(R.id.first_name);
//當且視圖控件指向item,即完成綁定
view.setTag(item);
}else{
//若當前視圖不爲空,那麼直接從當前view中綁定控件,以便執行相應操作。
item = (ListItem)view.getTag();
}
/**我可可以在這裏執行響應的頁面操作,比如賦值,刪除,點擊事件等
* 下面我會一一舉個小例子
*/
/**
* 賦值
* 這裏的數據可以是從本地數據庫中,服務端,網絡,或者是程序自動生成的
*
*/
Up up = first.get(position);
item.tView.setText(up.getStrName());
item.iView.setImageResource(R.drawable.ic_launcher);
item.bt_delect.setText("刪除");
item.bt_click.setText(up.getStrNum());
/**
* 添加監聽
* 在開發過程中,一般爲了方便起見,都是將監聽操作寫在Adapter裏面,主要是方便,你也可以在外部通過OnItemClickListener對視圖註冊監聽
* */
item.bt_click.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//我在這讓輸出一個提示,打擊可以在這裏進行任何操作。
Toast.makeText(context, "你選擇了"+position, Toast.LENGTH_LONG).show();
}
});
/**
* 刪除
* 對於LsitView和GridView操作,刪除操作常用的事,而BaseAdapter也提供給我們兩種刪除的反饋機制
* 分別是notifyDataSetInvalidated()和notifyDataSetChanged()
* 這兩個方法可以直接使用,也可以對他們進行重寫,在這裏我就不重寫了
* 他們的區別是出發後的機制不同
* notifyDataSetChanged():重繪當前可見區域,它是通過調用getView來刷新
* notifyDataSetInvalidated():重繪控件,他是通過在內部調用onChanged事件
* */
item.bt_delect.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
first.remove(position);
notifyDataSetChanged();
}
});
return view;
}
//想重寫的話,在這裏添加內容即可
@Override
public void notifyDataSetChanged() {
// TODO Auto-generated method stub
super.notifyDataSetChanged();
}
}
package com.teach.down;
import java.util.ArrayList;
import java.util.List;
public class Down {
private String strName;
public Down(String strName) {
super();
this.strName = strName;
}
public String getStrName() {
return strName;
}
public void setStrName(String strName) {
this.strName = strName;
}
public static List<Down> getString (int count){
List<Down> down = new ArrayList<Down>();
for(int i=0;i<count;i++)
down.add(new Down("男"+i+"號"));
return down;
}
}
package com.teach.down;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.List;
import com.teach.demo.R;
import com.teach.up.Up;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
public class DownAdapter extends BaseAdapter{
private Context context;
private LayoutInflater inflater;
private List<Down> first;
private GridView grid;
private static int selectItem;
//設定列表項所需控件,要和自己設計 的列表項控件一致。
//在這裏我偷懶一下,就放三個。
static class GridItem{
TextView tView;
ImageView iView;
}
/**設置構造函數,對pUAdapter的內容進行綁定
* @param context 決定當前Actvity類
* @param first 所需加載啊的列表項數據
* @param list 當前適配器匹配的視圖類型,這裏換成GridView類型的話,顯示的列表項就會是九宮格風格
*/
public DownAdapter(Context context,List<Down> first,GridView grid){
this.context = context;
//指定當前LayoutInflater服務的Activity,一遍後面初始化相應的視圖。
this.inflater = LayoutInflater.from(context);
this.grid = grid;
this.first = first;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return first.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return first.get(position);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
/**
* @param position 指定列表項的當前所處位置
* @param view 指定視圖,即當前列表項
* @param parents 指定視圖所屬的父類,即當前列表項所屬的列表
*
* 此處是Adapter的關鍵所在,任何視圖在配置Adapter時,
* 都是通過調用Adapter的getView方法,將視圖中所需的每個小項組裝成定義後的樣子。
*/
@Override
public View getView(int position, View view, ViewGroup parents) {
// TODO Auto-generated method stub
GridItem gitem = null;
//如果當前爲空,則對視圖進行初始化
if(view == null){
//指定當前視圖所對應xml文件。並初始化其中的控件,這個view就是一個小的列表項
view = inflater.inflate(R.layout.view_first_downitem, null);
gitem = new GridItem();
gitem.iView = (ImageView)view.findViewById(R.id.first_downiv);
gitem.tView = (TextView)view.findViewById(R.id.first_downtv);
//當且視圖控件指向item,即完成綁定
view.setTag(gitem);
}else{
//若當前視圖不爲空,那麼直接從當前view中綁定控件,以便執行相應操作。
gitem = (GridItem)view.getTag();
}
gitem.iView.setImageResource(R.drawable.ic_launcher);
gitem.tView.setText(first.get(position).getStrName().toString());
//點擊高亮效果
if(position == selectItem){
view.setBackgroundColor(Color.CYAN);
}else{
view.setBackgroundColor(Color.WHITE);
}
return view;
}
//獲取當前點擊的項目位置
public static void getSelectItem(int select){
selectItem = select;
}
}
同時我們要建立兩個列表項的xml文件,在這個xml文件中你所構造的佈局,就是應用到ListView或GridView的項目格式,他們的每一項都將按照這個佈局顯示出來
這是view_first_downitem.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- @author Arthur Lee -->
<TextView
android:id="@+id/first_downtv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/first_downiv"
android:layout_below="@+id/first_downiv"
android:text="TextView" />
<ImageView
android:id="@+id/first_downiv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />
</RelativeLayout>
這是view_first_upitem.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- @author Arthur Lee -->
<ImageView
android:id="@+id/first_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="66dp"
android:layout_marginTop="89dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/first_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/first_photo"
android:layout_marginLeft="14dp"
android:layout_marginTop="14dp"
android:layout_toRightOf="@+id/first_photo"
android:text="TextView" />
<Button
android:id="@+id/first_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/first_photo"
android:layout_marginLeft="27dp"
android:layout_toRightOf="@+id/first_name"
android:text="Button" />
<Button
android:id="@+id/first_delect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/first_click"
android:layout_alignBottom="@+id/first_click"
android:layout_toRightOf="@+id/first_click"
android:text="Button" />
</RelativeLayout>
下面我們就要對第一講裏的FirstFragment進行重寫
package com.teach.demo;
/**
* @author Arthur Lee
* @time 04/08/2014
* */
import java.util.ArrayList;
import java.util.List;
import com.teach.down.Down;
import com.teach.down.DownAdapter;
import com.teach.up.Up;
import com.teach.up.UpAdapter;
import com.teach.up.UpSerivce;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.ListView;
public class FirstFragment extends Fragment{
//緩存視圖
private View view,upview,downview;
private Context context;
/*
*ListView相關控件 */
private List<Up> up;
private ListView listview;
private UpAdapter Uadapter;
/*
* GridView相關控件*/
private List<Down> down;
private GridView gridview;
private DownAdapter Dadapter;
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
//如果當前視圖爲空,初始化視圖
if(view == null){
//指定當前視圖在viewpager中顯示的是view_first。xml,通過LayoutInflater來指定.
view = inflater.inflate(R.layout.view_first, container,false);
}
//指定當前視圖的父類,以便調用父類的移除功能。
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
upview = (View)view.findViewById(R.id.firist_upview);
listview = (ListView)upview.findViewById(R.id.first_up);
up = new ArrayList<Up>();
up = UpSerivce.getString(5);
Uadapter = new UpAdapter(getActivity(),up,listview);
//此時的listview已經具有了監聽功能
listview.setAdapter(Uadapter);
downview = (View)view.findViewById(R.id.firist_downview);
gridview = (GridView)downview.findViewById(R.id.first_down);
down = new ArrayList<Down>();
down = Down.getString(5);
Dadapter = new DownAdapter(getActivity(),down,gridview);
gridview.setAdapter(Dadapter);
//在這裏我使用了和ListView不同的監聽註冊方法
gridview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
// TODO Auto-generated method stub
Dadapter.getSelectItem(position);
//通知適配器控件發生變化。無需重繪視圖。
Dadapter.notifyDataSetInvalidated();
}
});
return view;
}
}
運行模擬器,效果圖如下:
還是那句話:我不是一名好的程序員,因爲我只會默默奉獻