Android界面中有時(shí)候需要顯示稍微復(fù)雜的界面時(shí),就需要我們自定義一個(gè)adapter,而此adapter就要繼承BaseAdapter,重新其中的方法. Android中Adapter類其實(shí)就是把數(shù)據(jù)源綁定到指定的View上,然后再返回該View,而返回來的這個(gè)View就是ListView中的某一行item。這里返回來的View正是由我們的Adapter中的getView方法返回的。這樣就會(huì)容易理解數(shù)據(jù)是怎樣一條一條顯示在ListView中的。 在完成這篇文章中的例子之后,我思考了很長時(shí)間,關(guān)于重寫一個(gè)adapter,這其中真的有很多講究,遇到一處不懂的都會(huì)查閱很長時(shí)間,但也不能保證我已經(jīng)把其中的重中之重已經(jīng)找完了,只要你想延伸都可以發(fā)現(xiàn)其中的無限..... 問題1:為什么我們要重寫一個(gè)adapter? 問題2:android中這么多adapter,什么情況下該重寫哪一個(gè)adapter(ArrayAdapter/SimpleAdapter/SimpleCursorAdapter...)? 問題3:我們重寫的adapter為什么是一個(gè)內(nèi)部類,是否建議把a(bǔ)dapter做成一個(gè)內(nèi)部類? 問題4:理解應(yīng)用中的數(shù)據(jù)源一般都會(huì)用一個(gè)Map類型的List,有何意途? 問題5:通過adapter是怎樣做到把一條一條的item放到ListView中的? 問題6:理解重寫adapter時(shí),重寫的幾個(gè)方法(getCount()/getItem()/getItemId()/getView())? 問題7:理解ListView使用adapter的機(jī)制 案例概覽步驟: 1)創(chuàng)建2個(gè)layout,一個(gè)是界面頂部的顯示,一個(gè)是ListView中的內(nèi)容 1.1)ListView_header.xml(注:自我感覺界面中的控件的位置擺放與layout_width/layout_height/orientation/gravity/layout_gravity的屬性設(shè)置關(guān)系非常大,一定要注意每個(gè)屬性的用法) <?xml version="1.0" encoding="UTF-8"?> <!-- 第一個(gè)LinearLayout,充當(dāng)父容器,要包攬兩行,因此設(shè)置其 android:orientation為 縱向--> <LinearLayout xmlns:android="http://schemas./apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <!-- 第二個(gè)LinearLayout android:gravity 表示該LinearLayout中的類容相對(duì)于該LinearLayout 水平居中 android:layout_gravity 表示的是該LinearLayout相對(duì)于它上面的父容器(這里是第一個(gè)LinearLayout)水平居中 --> <LinearLayout android:id="@+id/toprow" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_horizontal"> <TextView android:id="@+id/quna" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff9966ff" android:textSize="25dp" android:text="@string/places"/> <!-- 用一個(gè)圖片按鈕 --> <ImageButton android:id="@+id/goBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/quna"/> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/placesList" android:textColor="#ff9966ff" android:textSize="20dp"/> <ListView android:id="@+id/list_places" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout> 1.2)listview_item.xml <?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android="http://schemas./apk/res/android" android:orientation="horizontal" //此屬性的設(shè)置非常重要,決定里面的控件橫向擺放 android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- android:layout_margin設(shè)置圖片與旁邊文章的距離 --> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp"/> <LinearLayout android:orientation="vertical" //也很重要決定里面的兩個(gè)textview豎著放 android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff3399ff" android:textSize="20dp"/> <TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff3399ff" android:textSize="13dp"/> </LinearLayout> <!-- 注意此處button的屬性android:layout_gravity的用法 ,這里設(shè)置了都沒效果 這里不是很理解為什么要在加一個(gè)LinearLayout,里面的button才可以居右?? 而且LinearLayout的width必須為fill_parent才可以 --> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <Button android:id="@+id/viewBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_select" android:layout_gravity="bottom|right"/> </LinearLayout> </LinearLayout> 2)、寫java class,開發(fā)activity(建一個(gè)class繼承Activity,添加click事件的時(shí)候還要實(shí)現(xiàn)onClickListener接口) 2.1) 重寫onCreate方法-----------------------------------------------> private ListView listView; private ImageButton goBtn; private List<Map<String, Object>> testData; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listview_header);//這里運(yùn)行該項(xiàng)目的時(shí)候,讓其顯示listview_header.xml界面(layout),然后再將listview要顯示的item項(xiàng)加到里面 //獲得listview_header.xml中的ListView控件 listView = (ListView) findViewById(R.id.list_places); //獲得imageButton給它添加click事件 goBtn = (ImageButton) findViewById(R.id.goBtn); goBtn.setOnClickListener(new OnClickListener() { //這里只是做出了簡單的彈出框 @Override public void onClick(View v) { new AlertDialog.Builder(BaseAdapterTest2.this).setTitle("想去的國家:") .setMessage("i want to go France") .setPositiveButton("確定", null).sho(); } }); //數(shù)據(jù)源 testData = buildData(); MyAdapter adapter = new MyAdapter(this); //通過setAdapter而把數(shù)據(jù)綁定到ListView中 listView.setAdapter(adapter); } 2.2)創(chuàng)建數(shù)據(jù),注意這里為什么要是Map類型的List集合 private List<Map<String, Object>> buildData(){ List<Map<String, Object>> data = new ArrayList<Map<String,Object>>(); Map<String, Object> map = new HashMap<String, Object>(); map.put("title", "中國"); map.put("info", "China"); map.put("image", R.drawable.p6); data.add(map); map = new HashMap<String, Object>(); map.put("title", "英國"); map.put("info", "England"); map.put("image", R.drawable.p7); data.add(map); map = new HashMap<String, Object>(); map.put("title", "美國"); map.put("info", "America"); map.put("image", R.drawable.p9); map = new HashMap<String, Object>(); map.put("title", "荷蘭"); map.put("info", "Dutch"); map.put("image", R.drawable.p9); data.add(map); map = new HashMap<String, Object>(); map.put("title", "新西蘭"); map.put("info", "New Zealand"); map.put("image", R.drawable.p7); data.add(map); data.add(map); return data; } 2.3)寫自定義adapter(它是一個(gè)內(nèi)部類,繼承自BaseAdapter,并不確定是否自定義的adapter一般都是繼承它),尤其注意其中的幾個(gè)方法 public class MyAdapter extends BaseAdapter{ private LayoutInflater inflater;//這個(gè)一定要懂它的用法及作用 //構(gòu)造函數(shù):要理解(這里構(gòu)造方法的意義非常強(qiáng)大,你也可以傳一個(gè)數(shù)據(jù)集合的參數(shù),可以根據(jù)需要來傳參數(shù)) public MyAdapter(Context context){ this.inflater = LayoutInflater.from(context); } //這里的getCount方法是程序在加載顯示到ui上時(shí)就要先讀取的,這里獲得的值決定了listview顯示多少行 @Override public int getCount() { //在實(shí)際應(yīng)用中,此處的返回值是由從數(shù)據(jù)庫中查詢出來的數(shù)據(jù)的總條數(shù) return testData.size(); } //根據(jù)ListView所在位置返回View @Override public Object getItem(int position) { // TODO Auto-generated method stub return this.testData.get(position); } //根據(jù)ListView位置得到數(shù)據(jù)源集合中的Id @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } //重寫adapter最重要的就是重寫此方法,此方法也是決定listview界面的樣式的 @Override public View getView(int position, View convertView, ViewGroup parent) { //有很多例子中都用到這個(gè)holder,理解下?? ViewHolder holder = null; //思考這里為何要判斷convertView是否為空 ?? if(convertView == null){ holder = new ViewHolder(); //把vlist layout轉(zhuǎn)換成View【LayoutInflater的作用】 convertView = inflater.inflate(R.layout.vlist, null); //通過上面layout得到的view來獲取里面的具體控件 holder.image = (ImageView) convertView.findViewById(R.id.image); holder.title = (TextView) convertView.findViewById(R.id.title); holder.info = (TextView) convertView.findViewById(R.id.info); holder.viewBtn = (Button) convertView.findViewById(R.id.viewBtn); //不懂這里setTag什么意思?? convertView.setTag(holder); } else{ holder = (ViewHolder) convertView.getTag(); } //這里testData.get(position).get("title1")),其實(shí)就是從list集合(testData)中取出對(duì)應(yīng)索引的map,然后再根據(jù)鍵值對(duì)取值 holder.image.setBackgroundResource((Integer) testData.get(position).get("image1")); holder.title.setText((String) testData.get(position).get("title1")); holder.info.setText((String) testData.get(position).get("info1")); //為listview上的button添加click監(jiān)聽 holder.viewBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ..... } }); return convertView; } } 到此,整個(gè)案例的關(guān)鍵部分已經(jīng)全部出來了,做的過程中有很多地方?jīng)]有想通也都做有注釋,做完以后,多揣摩了幾遍才將就理解,嘿嘿 ![]() 重點(diǎn)提出一個(gè)疑問:不能確定是否在onCreate方法中的 new Adapter,在里面表面上看是只調(diào)用了一次而進(jìn)入自定義Adapter中調(diào)用(其實(shí)也沒有直接調(diào)用,自己想的它可能有一個(gè)自己的內(nèi)部機(jī)制,每new完一個(gè)Adapter就直接調(diào)用getCount/getView方法嗎)它里面的方法 ,調(diào)用一次就會(huì)繪制一個(gè)ListView中的一個(gè)item項(xiàng),那么有很多條item的時(shí)候,它是否要那樣循環(huán)調(diào)用很多次呢?? getView方法中的參數(shù),convertview那塊。在初始化的時(shí)候,每顯示一行item項(xiàng)都會(huì)調(diào)用一次getView方法但每次調(diào)用的時(shí)候convertview為null(因?yàn)檫€沒有舊的view);如果屏幕移動(dòng)了之后,并且導(dǎo)致某些item項(xiàng)跑到屏幕外面,此時(shí)如果還有新的item需要產(chǎn)生,則這些item顯示時(shí)調(diào)用的getView方法中的convertview就不為null,而是那些移出到屏幕之外的view,我們所要做的就是將需要顯示的item項(xiàng)填充到移除屏幕外的(舊的)view中去,注意【convertview為null的不僅僅是初始化顯示的那些item,還有一些是已經(jīng)開始移入屏幕但還沒有view被回收的那些item】。 運(yùn)行結(jié)果: ![]() |
|