ListView、AdapterView、RecyclerView全面解析
原文鏈接:http://blog.csdn.net/carson_ho/article/details/51472640
AdapterView簡介
AdapterView本身是一個抽象類,AdapterView及其子類的繼承關系如下圖:
特征:
- AdapterView繼承自ViewGroup,本質是個容器
- AdapterView可以包含多個“列表項”,并將這多個列表項以合適的形式展示
- AdapterView顯示的列表項內容由Adapter提供
- 它派生的子類在用法上也基本相似,只是在顯示上有一定區別,因此把他們也歸為一類。
- 由AdapterView直接派生的三個類:
AbsListView、AbsSpinner、AdapterViewAnimator
都是抽象類,所以我們用的最多的也就是圖中第四行及以下的子類。
ListView簡介
1. 什么是ListView
即列表視圖,是Android開發中一種常用的視圖組件
2. ListView的作用
將所要展示的數據集合起來
以列表的形式展示到用戶界面上
3. 關于Adapter
- 定義:適配器
- 作用:作為View和數據之間的橋梁
由于ListView和所要展現的數據是分開的,不直接接觸,所以,Adapter的作用是把數據映射到ListView上,作為中介的作用,如下圖
3. ListView的工作原理
ListView、GridView、Spinner等AdapterView都只是容器,主要用于裝載要顯示的數據和顯示數據,而Apdater負責提供容器的內容
即AdapterView負責采用合適的方式顯示Adapter提供的內容。
在運行時,當需要顯示數據時,ListView會針對數據項向Adapter取出數據,從而加載到界面上。
試想下這么一個場景:如果把所有數據集合的信息都加載到View上,如果ListView要為每個數據都創建一個視圖,那么會占用非常多的內存
從上面可知,ListView不會為每一個數據創建一個視圖,為了節省空間和時間,Android采用了一個叫Recycler的組件。
工作原理:當屏幕需要顯示x個item時,那么ListView只會創建x+1個視圖,當第一個item離開屏幕時,此item的view就會被拿來重用(用于顯示下一個item(即第x+1個)的內容)。
工作原理實例
假如屏幕只能顯示7個item,那么ListView只會創建(7+1)個item的視圖。當第1個item離開屏幕時,此item的view就會被拿來重用(用于顯示第8個item的內容)。原理如下圖顯示
ListView的使用
1. 生成方式
生成列表視圖(ListView)的方式主要有兩種:
- 直接用ListView進行創建
- 讓Activity繼承ListActivity
2. xml文件配置信息
<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:background="#FFE1FF" android:orientation="vertical" > <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>AbsListView的常用屬性和相關方法
| android:choiceMode | 列表的選擇行為,默認:none沒有選擇行為 | 選擇方式: none:不顯示任何選中項 singleChoice:允許單選multipleChoice:允許多選multipleChoiceModal:允許多選 (把Activity里面adapter的第二個參數改成支持選擇的布局) |
| android:drawSelectorOnTop | 如果該屬性設置為true,選中的列表項將會顯示在上面 | |
| android:listSelector | 為點擊到的Item設置圖片 | 如果該屬性設置為true,選中的列表項將會顯示在上面 |
| android:fastScrollEnabled | 設置是否允許快速滾動 | 如果該屬性設置為true,將會顯示滾動圖標,并允許用戶拖動該滾動圖標進行快速滾動。 |
| android:listSelector | 指定被選中的列表項上繪制的Drawable | |
| android:scrollingCache | 滾動時是否使用緩存 | 如果設置為true,則在滾動時將會使用緩存 |
| android:stackFromBottom | 設置是否從底端開始排列列表項 | |
| android:transcriptMode | 指定列表添加新的選項的時候,是否自動滑動到底部,顯示新的選項。 | disabled:取消transcriptMode模式;默認的normal:當接受到數據集合改變的通知,并且僅僅當最后一個選項已經顯示在屏幕的時候,自動滑動到底部。 alwaysScroll:無論當前列表顯示什么選項,列表將會自動滑動到底部顯示最新的選項。 |
Listview提供的XML屬性:
| android:divider | 設置List列表項的分隔條(可用顏色分割,也可用圖片(Drawable)分割 | 不設置列表之間的分割線,可設置屬性為@null |
| android:dividerHeight | 用于設置分隔條的高度 | |
| android:background屬性 | 設置列表的背景 | |
| android:entries | 指定一個數組資源,Android將根據該數組資源來生成ListView | |
| android:footerDividerEnabled | 如果設置成false,則不在footer View之前繪制分隔條 | |
| andorid:headerDividerEnabled | 如果設置成false,則不再header View之前繪制分隔條 |
Adapter介紹
Adapter本身是一個接口,Adapter接口及其子類的繼承關系如下圖:
Adapter接口派生了ListAdapter和SpinnerAdapter兩個子接口
其中ListAdapter為AbsAdapter提供列表項,而SpinnerAdapter為AbsSpinner提供列表項
ArrayAdapter、SimpleAdapter、SimpleCursorAdapter、BaseAdapter都是常用的實現適配器的類
ArrayAdapter:簡單、易用的Adapter,用于將數組綁定為列表項的數據源,支持泛型操作
SimpleAdapter:功能強大的Adapter,用于將XML中控件綁定為列表項的數據源
SimpleCursorAdapter:與SimpleAdapter類似,用于綁定游標(直接從數據數取出數據)作為列表項的數據源
BaseAdapter:可自定義ListView,通用用于被擴展。擴展BaseAdapter可以對各個列表項進行最大程度的定制。
常用適配器介紹
1. ArrayAdapter
定義:簡單、易用的Adapter,用于將數組綁定為列表項的數據源,支持泛型操作
步驟
1、 在xml文件布局上實現ListView
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.example.carson_ho.adapte_demo.MainActivity"><ListView android:id="@+id/list_item"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="#f00"android:dividerHeight="1sp"android:headerDividersEnabled="false"></ListView> </RelativeLayout>2、 在MainActivity上定義一個鏈表,將所要展示的數據以存放在里面
3、 構造ArrayAdapter對象,設置適配器
4、 將LsitView綁定到ArrayAdapter上
創建ArrayAdapter對象要指定三個參數:
- context:代表方位Android應用的接口
- textViewRseourceld:資源ID,代表一個TextView
- 數組:列表項展示的數據
5、 在xml文件布局添加資源文件TextView,該TextView組件將作列表項的組件
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content">android:textSize="24sp" </TextView>最終效果圖
缺點:ArrayAdapter較為簡單,易用,但每個列表項只能是TextView,功能實現的局限性非常大。
2. SimpleAdapter
定義:功能強大的Adapter,用于將XML中控件綁定作為列表項的數據源
特點:可對每個列表項進行定制(自定義布局),能滿足大多數開發的需求場景,靈活性較大
步驟
1、 在xml文件布局上實現ListView
2、 根據實際需求定制列表項:實現ListView每行的xml布局(即item布局)
<?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"><TextView android:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingLeft="14dp"android:textSize="17sp"/><TextView android:id="@+id/address"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/name"android:textSize="17sp"/><TextView android:id="@+id/lowerest_wholesale"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/address"android:textSize="17sp"/><TextView android:id="@+id/price"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/address"android:textSize="17sp"/><ImageView android:id="@+id/picture"android:layout_width="115dp"android:layout_height="86dp"android:layout_alignParentRight="true"/> </RelativeLayout>3、 定義一個HashMap構成的列表以鍵值對的方式存放數據
4、 構造SimpleAdapter對象,設置適配器
5、 將LsitView綁定到SimpleAdapter上
結果顯示
BaseAdapter
定義:可自定義ListView,通用用于被擴展。擴展BaseAdapter可以對各個列表項進行最大程度的定制
使用步驟:
- 定義主xml布局
- 根據需要定義ListView每行所實現的xml布局
- 定義一個Adapter類繼承BaseAdapter,重寫里面的方法。
- 定義一個HashMap構成的列表,將數據以鍵值對的方式存放在里面。
- 構造Adapter對象,設置適配器。
- 將LsitView綁定到Adapter上。
先定義一個Adapter類繼承BaseAdapter,并重寫里面的方法
使用BaseAdapter必須寫一個類繼承它,同時BaseAdapter是一個抽象類,繼承它必須實現它的方法。
class MyAdapter extends BaseAdapter {private LayoutInflater mInflater;//得到一個LayoutInfalter對象用來導入布局//構造函數public MyAdapter(Context context,ArrayList<HashMap<String, Object>> listItem) {this.mInflater = LayoutInflater.from(context);this.listItem = listItem;}//聲明構造函數@Overridepublic int getCount() {return listItem.size();}//這個方法返回了在適配器中所代表的數據集合的條目數@Overridepublic Object getItem(int position) {return listItem.get(position);}//這個方法返回了數據集合中與指定索引position對應的數據項@Overridepublic long getItemId(int position) {return position;}//這個方法返回了在列表中與指定索引對應的行id@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return null;}//這個方法返回了指定索引對應的數據項的視圖,還沒寫完 }這里主要講一下BaseAdapter里必須要重寫的4個方法
- BaseAdapter的靈活性就在于它要重寫很多方法,其中最重要的即為getView()方法。
- 我們結合上述重寫的4個方法了解下系統繪制ListView的原理:
當系統開始繪制ListView的時候,首先調用getCount()方法。得到它的返回值,即ListView的長度。
系統調用getView()方法,根據這個長度逐一繪制ListView的每一行。(如果讓getCount()返回1,那么只顯示一行)。
getItem()和getItemId()則在需要處理和取得Adapter中的數據時調用。
那么getView()如何使用呢?如果有10000行數據,就繪制10000次?這肯定會極大的消耗資源,導致ListView滑動非常的慢,那應該怎么做呢?可以使用BaseAdapter進行優化ListView的顯示。
以下將使用4種重寫方法來說明getView()的使用
重寫getView()的第一種方法
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View item = mInflater.inflate(R.layout.item,null);ImageView img = (ImageView)item.findViewById(R.id.ItemImage);TextView title = (TextView)item.findViewById(R.id.ItemTitle);TextView test = (TextView)item.findViewById(R.id.ItemText);Button btn = (Button) item.findViewById(R.id.ItemBottom);img.setImageResource((Integer) listItem.get(position).get("ItemImage"));title.setText((String) listItem.get(position).get("ItemTitle"));test.setText((String) listItem.get(position).get("ItemText"));return item;}//這個方法返回了指定索引對應的數據項的視圖這種方法每次getView()都要findViewById和重新繪制一個View,當列表項數據量很大的時候會嚴重影響性能,造成下拉很慢,所以數據量大的時候不推薦用這種方式。
重寫getView()的第二種方法:使用convertView作為緩存進行優化
getView()返回值是一個View,把它作為輸入參數并放到getView()輸入參數里,形成反饋。這樣就形成了Adapter的itemView重用機制,減少了重繪View的次數。
這種方法和第一種相比減少了重繪View的次數,但是還是每一次都要findViewById
重寫getView()第三種方法
通過convertView+ViewHolder來實現緩存進而進行優化
convertView緩存了View,ViewHolder相當于更加具體的緩存:View里的組件,即把View和View的組件一并進行緩存,那么重用View的時候就不用再重繪View和View的組件(findViewById)
這種方法就既減少了重繪View,又減少了findViewById的次數,所以這種方法是最能節省資源的,所以非常推薦大家使用通過convertView+ViewHolder來重寫getView()
利用convertView+ViewHolder來重寫getView()的實現BaseAdapter的具體實現代碼:
定義主xml的布局 activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <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:background="#FFFFFF"android:orientation="vertical" ><ListView android:id="@+id/listView1"android:layout_width="match_parent"android:layout_height="match_parent" /> </LinearLayout>根據需要,定義ListView每行所實現的xml布局(item布局) item.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"><ImageView android:layout_alignParentRight="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/ItemImage"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="按鈕"android:id="@+id/ItemBottom"android:focusable="false"android:layout_toLeftOf="@+id/ItemImage" /><TextView android:id="@+id/ItemTitle"android:layout_height="wrap_content"android:layout_width="fill_parent"android:textSize="20sp"/><TextView android:id="@+id/ItemText"android:layout_height="wrap_content"android:layout_width="fill_parent"android:layout_below="@+id/ItemTitle"/> </RelativeLayout>定義一個Adapter類繼承BaseAdapter,重寫里面的方法。 (利用convertView+ViewHolder來重寫getView())
MyAdapter.java
package scut.learnlistview;import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView;import java.util.ArrayList; import java.util.HashMap;/*** Created by yany on 2016/4/11.*/ class MyAdapter extends BaseAdapter {private LayoutInflater mInflater;//得到一個LayoutInfalter對象用來導入布局 ArrayList<HashMap<String, Object>> listItem;public MyAdapter(Context context,ArrayList<HashMap<String, Object>> listItem) {this.mInflater = LayoutInflater.from(context);this.listItem = listItem;}//聲明構造函數@Overridepublic int getCount() {return listItem.size();}//這個方法返回了在適配器中所代表的數據集合的條目數@Overridepublic Object getItem(int position) {return listItem.get(position);}//這個方法返回了數據集合中與指定索引position對應的數據項@Overridepublic long getItemId(int position) {return position;}//這個方法返回了在列表中與指定索引對應的行id//利用convertView+ViewHolder來重寫getView()static class ViewHolder{public ImageView img;public TextView title;public TextView text;public Button btn;}//聲明一個外部靜態類@Overridepublic View getView(final int position, View convertView, final ViewGroup parent) {ViewHolder holder ;if(convertView == null){holder = new ViewHolder();convertView = mInflater.inflate(R.layout.item, null);holder.img = (ImageView)convertView.findViewById(R.id.ItemImage);holder.title = (TextView)convertView.findViewById(R.id.ItemTitle);holder.text = (TextView)convertView.findViewById(R.id.ItemText);holder.btn = (Button) convertView.findViewById(R.id.ItemBottom);convertView.setTag(holder);}else {holder = (ViewHolder)convertView.getTag();}holder.img.setImageResource((Integer) listItem.get(position).get("ItemImage"));holder.title.setText((String) listItem.get(position).get("ItemTitle"));holder.text.setText((String) listItem.get(position).get("ItemText"));holder.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {System.out.println("你點擊了選項"+position);//bottom會覆蓋item的焦點,所以要在xml里面配置android:focusable="false"}});return convertView;}//這個方法返回了指定索引對應的數據項的視圖 }4、在MainActivity里:
- 定義一個HashMap構成的列表,將數據以鍵值對的方式存放在里面。
- 構造Adapter對象,設置適配器。
- 將LsitView綁定到Adapter上。
MainActivity.java
package scut.learnlistview;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.SimpleAdapter;import java.util.ArrayList; import java.util.HashMap; import java.util.List;public class MainActivity extends AppCompatActivity {private ListView lv;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv = (ListView) findViewById(R.id.listView1);/*定義一個以HashMap為內容的動態數組*/ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();/*在數組中存放數據*/for (int i = 0; i < 100; i++) {HashMap<String, Object> map = new HashMap<String, Object>();map.put("ItemImage", R.mipmap.ic_launcher);//加入圖片map.put("ItemTitle", "第" + i + "行");map.put("ItemText", "這是第" + i + "行");listItem.add(map);}MyAdapter adapter = new MyAdapter(this, listItem);lv.setAdapter(adapter);//為ListView綁定適配器lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {System.out.println("你點擊了第" + arg2 + "行");//設置系統輸出點擊的行}});} }運行結果
點擊輸出結果:
RecyclerView介紹
1. 定義
RecyclerView是Google推出用來代替ListView組件的,是一個強大的滑動組件。
RecyclerView強制使用了ViewHolder,直接把viewholder的實現封裝起來,用戶只要實現自己的viewholder就可以了,該組件會自動幫你回收復用每一個item。
2. 工作原理
當屏幕需要顯示x個item時,那么ListView只會創建x+1個視圖,當第一個item離開屏幕時,此item的view就會被拿來重用(用于顯示下一個item(即第x+1個)的內容)。
3. 工作原理實例
假如屏幕只能顯示7個item,那么ListView只會創建(7+1)個item的視圖。當第1個item離開屏幕時,此item的view就會被拿來重用(用于顯示第8個item的內容)。原理如下圖顯示
4. RecyclerView的重要概念介紹
RecyclerView.Adapter
和ListView一樣,RecyclerView一樣需要適配器,而且這個適配器強制要求了我們必須要用Viewholder,讓性能得到優化,而且getView方法不需自己寫,我們只需要寫好Viewholder,View的復用已經封裝好了。
LayoutManager
管理布局,設置為LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager可以輕易地實現ListView,GridView以及流式布局的列表效果。它還可以管理滾動和循環利用。
ItemAnimator
這個類可以實現增刪動畫,而且不想設置的話它的默認效果已經很好了。
5. 優缺點
優點 : 有了ListView、GridView為什么還需要RecyclerView這樣的控件呢?優點在于
- item復用性高
把ViewHolder的實現封裝起來,規范了ViewHolder,把item的view寫入ViewHolder中,可以通過復用ViewHolder來實現view的復用 - 靈活、可定制化高、可拓展性高
整體上看RecyclerView架構,提供了一種插拔式的體驗:高度的解耦,異常的靈活: - 控制其顯示的方式-通過布局管理器LayoutManager
- 控制Item間的間隔(可繪制)-通過ItemDecoration
- 控制Item增刪的動畫- 通過ItemAnimator
問:相比較于ListView,RecyclerView基本需要上面一系列步驟進行設置,而ListView可能只需要去設置一個adapter就能正常使用。那么為什么會添加這么多的步驟呢?
答:從名字上看RecyclerView,即回收循環視圖,也就是說RecyclerView只管回收與復用View,其他的你可以自己去設置,可以看出其高度的解耦,給予你充分的定制自由
缺點: RecyclerView實現控制點擊、長按事件較為麻煩,需要自己寫
使用實例
使用RecyclerView的步驟:
- 定義主xml布局
- 根據需要定義RecyclerView每行所實現的xml布局
- 定義一個Adapter類繼承RecyclerView.Adapter,重寫里面的方法。
- 定義一個HashMap構成的列表,將數據以鍵值對的方式存放在里面。
- 構造Adapter對象,設置適配器。
- 將RecyclerView綁定到Adapter上。
Demo的源碼下載:https://github.com/Carson-Ho/RecyclerView
個人推薦先fork下來再對著下面的分析看,效果會更好哦!
步驟1. 定義主xml布局
activity_main.xml
<RelativeLayout 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"tools:context="${relativePackage}.${activityClass}" ><android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:scrollbars="horizontal"/><!--設置一個RecyclerView--></RelativeLayout>在AndroidStudio1.5使用support-v7包:
- 右鍵文件目錄的app目錄進入Moudle Setting
- 在Dependencies里面加入com.android.support:recyclerview-v7:23.1.1包。
步驟2. 根據需要定義RecyclerView每行所實現的xml布局(item布局)
list_cell.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent"android:layout_height="match_parent"><ImageView android:layout_alignParentRight="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/ItemImage"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="New Text"android:id="@+id/Itemtitle" /><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="New Text"android:id="@+id/Itemtext"android:layout_below="@+id/Itemtitle"/> </RelativeLayout> </LinearLayout>步驟3. 定義一個Adapter類繼承 RecyclerView.Adapter,重寫里面的方法。
MyAdapter.Java
package scut.receiverview;import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView;import java.util.ArrayList; import java.util.HashMap;/*** Created by yany on 2016/4/11.*/ public class MyAdapter extends RecyclerView.Adapter {private LayoutInflater inflater;private ArrayList<HashMap<String, Object>> listItem;private MyItemClickListener myItemClickListener;public MyAdapter(Context context, ArrayList<HashMap<String, Object>> listItem) {inflater = LayoutInflater.from(context);this.listItem = listItem;}//構造函數,傳入數據//定義Viewholderclass Viewholder extends RecyclerView.ViewHolder {private TextView Title, Text;private ImageView ima;public Viewholder(View root) {super(root);Title = (TextView) root.findViewById(R.id.Itemtitle);Text = (TextView) root.findViewById(R.id.Itemtext);ima = (ImageView) root.findViewById(R.id.ItemImage);root.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (myItemClickListener != null)myItemClickListener .onItemClick(v,getPosition());}}//監聽到點擊就回調MainActivity的onItemClick函數);}public TextView getTitle() {return Title;}public TextView getText() {return Text;}public ImageView getIma() {return ima;}}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {return new Viewholder(inflater.inflate(R.layout.list_cell, null));}//在這里把ViewHolder綁定Item的布局@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {Viewholder vh = (Viewholder) holder;vh.Title.setText((String) listItem.get(position).get("ItemTitle"));vh.Text.setText((String) listItem.get(position).get("ItemText"));vh.ima.setImageResource((Integer) listItem.get(position).get("ItemImage"));}//在這里綁定數據到ViewHolder里面@Overridepublic int getItemCount() {return listItem.size();}//返回Item數目public void setOnItemClickListener(MyItemClickListener listener){myItemClickListener = listener;}//綁定MainActivity傳進來的點擊監聽器 }實現點擊事件:
MyItemClickListener.java接口:用來實現點擊事件
package scut.receiverview;import android.view.View;public interface MyItemClickListener {public void onItemClick(View view,int postion); }步驟4:在MainActicity.java里:
- 定義一個HashMap構成的列表,將數據以鍵值對的方式存放在里面。
- 構造Adapter對象,設置適配器
- 將RecyclerView綁定到Adapter上
MainActicity.java
package scut.receiverview;import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Toast;import java.util.ArrayList; import java.util.HashMap;public class MainActivity extends AppCompatActivity implements MyItemClickListener {private RecyclerView Rv;private ArrayList<HashMap<String,Object>> listItem;private MyAdapter myAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();initView();}public void initData(){listItem = new ArrayList<HashMap<String, Object>>();/*在數組中存放數據*/for (int i = 0; i < 100; i++) {HashMap<String, Object> map = new HashMap<String, Object>();map.put("ItemTitle", "第" + i + "行");map.put("ItemText", "這是第" + i + "行");map.put("ItemImage",R.mipmap.ic_launcher);listItem.add(map);}}public void initView(){//為ListView綁定適配器myAdapter = new MyAdapter(this,listItem);myAdapter.setOnItemClickListener(this);Rv.setAdapter(myAdapter); Rv = (RecyclerView) findViewById(R.id.my_recycler_view);//使用線性布局LinearLayoutManager layoutManager = new LinearLayoutManager(this);Rv.setLayoutManager(layoutManager);Rv.setHasFixedSize(true);Rv.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation()));//用類設置分割線 //Rv.addItemDecoration(new DividerItemDecoration(this, R.drawable.list_divider)); //用已有圖片設置分割線}@Overridepublic void onItemClick(View view, int postion) {//點擊事件的回調函數System.out.println("點擊了第"+postion+"行");Toast.makeText(this, (String)listItem.get(postion).get("ItemText"), Toast.LENGTH_SHORT).show();}}如果自己畫了分割線就可以直接添上去,不需要寫這個類
DividerItemDecoration.java:
package scut.receiverview;import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.View;public class DividerItemDecoration extends RecyclerView.ItemDecoration {/** RecyclerView的布局方向,默認先賦值* 為縱向布局* RecyclerView 布局可橫向,也可縱向* 橫向和縱向對應的分割想畫法不一樣* */private int mOrientation = LinearLayoutManager.VERTICAL ;/*** item之間分割線的size,默認為1*/private int mItemSize = 1 ;/*** 繪制item分割線的畫筆,和設置其屬性* 來繪制個性分割線*/private Paint mPaint ;/*** 構造方法傳入布局方向,不可不傳* @param context* @param orientation*/public DividerItemDecoration(Context context,int orientation) {this.mOrientation = orientation;if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){throw new IllegalArgumentException("請傳入正確的參數") ;}mItemSize = (int) TypedValue.applyDimension(mItemSize, TypedValue.COMPLEX_UNIT_DIP,context.getResources().getDisplayMetrics());mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ;mPaint.setColor(Color.BLUE);/*設置填充*/mPaint.setStyle(Paint.Style.FILL);}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {if(mOrientation == LinearLayoutManager.VERTICAL){drawVertical(c,parent) ;}else {drawHorizontal(c,parent) ;}}/*** 繪制縱向 item 分割線* @param canvas* @param parent*/private void drawVertical(Canvas canvas,RecyclerView parent){final int left = parent.getPaddingLeft() ;final int right = parent.getMeasuredWidth() - parent.getPaddingRight() ;final int childSize = parent.getChildCount() ;for(int i = 0 ; i < childSize ; i ++){final View child = parent.getChildAt( i ) ;RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();final int top = child.getBottom() + layoutParams.bottomMargin ;final int bottom = top + mItemSize ;canvas.drawRect(left,top,right,bottom,mPaint);}}/*** 繪制橫向 item 分割線* @param canvas* @param parent*/private void drawHorizontal(Canvas canvas,RecyclerView parent){final int top = parent.getPaddingTop() ;final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom() ;final int childSize = parent.getChildCount() ;for(int i = 0 ; i < childSize ; i ++){final View child = parent.getChildAt( i ) ;RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();final int left = child.getRight() + layoutParams.rightMargin ;final int right = left + mItemSize ;canvas.drawRect(left,top,right,bottom,mPaint);}}/*** 設置item分割線的size* @param outRect* @param view* @param parent* @param state*/@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {if(mOrientation == LinearLayoutManager.VERTICAL){outRect.set(0,0,0,mItemSize);}else {outRect.set(0,0,mItemSize,0);}} }效果輸出圖
總結
本文對ListView、AdapterView、RecyclerView進行了全面整理,接下來我會介紹繼續介紹Android開發中的相關知識,有興趣可以繼續關注Carson_Ho的安卓開發筆記
總結
以上是生活随笔為你收集整理的ListView、AdapterView、RecyclerView全面解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 依赖注入Dagger2详解
- 下一篇: RecyclerView