日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ListView、AdapterView、RecyclerView全面解析

發(fā)布時(shí)間:2025/4/16 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ListView、AdapterView、RecyclerView全面解析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文鏈接:http://blog.csdn.net/carson_ho/article/details/51472640

AdapterView簡介

AdapterView本身是一個(gè)抽象類,AdapterView及其子類的繼承關(guān)系如下圖:

特征:

  • AdapterView繼承自ViewGroup,本質(zhì)是個(gè)容器
  • AdapterView可以包含多個(gè)“列表項(xiàng)”,并將這多個(gè)列表項(xiàng)以合適的形式展示
  • AdapterView顯示的列表項(xiàng)內(nèi)容由Adapter提供
  • 它派生的子類在用法上也基本相似,只是在顯示上有一定區(qū)別,因此把他們也歸為一類。
  • 由AdapterView直接派生的三個(gè)類:

AbsListView、AbsSpinner、AdapterViewAnimator

都是抽象類,所以我們用的最多的也就是圖中第四行及以下的子類。

ListView簡介

1. 什么是ListView

即列表視圖,是Android開發(fā)中一種常用的視圖組件

2. ListView的作用

將所要展示的數(shù)據(jù)集合起來
以列表的形式展示到用戶界面上

3. 關(guān)于Adapter

  • 定義:適配器
  • 作用:作為View和數(shù)據(jù)之間的橋梁

由于ListView和所要展現(xiàn)的數(shù)據(jù)是分開的,不直接接觸,所以,Adapter的作用是把數(shù)據(jù)映射到ListView上,作為中介的作用,如下圖

3. ListView的工作原理

ListView、GridView、Spinner等AdapterView都只是容器,主要用于裝載要顯示的數(shù)據(jù)和顯示數(shù)據(jù),而Apdater負(fù)責(zé)提供容器的內(nèi)容

即AdapterView負(fù)責(zé)采用合適的方式顯示Adapter提供的內(nèi)容。
在運(yùn)行時(shí),當(dāng)需要顯示數(shù)據(jù)時(shí),ListView會(huì)針對數(shù)據(jù)項(xiàng)向Adapter取出數(shù)據(jù),從而加載到界面上。

試想下這么一個(gè)場景:如果把所有數(shù)據(jù)集合的信息都加載到View上,如果ListView要為每個(gè)數(shù)據(jù)都創(chuàng)建一個(gè)視圖,那么會(huì)占用非常多的內(nèi)存
從上面可知,ListView不會(huì)為每一個(gè)數(shù)據(jù)創(chuàng)建一個(gè)視圖,為了節(jié)省空間和時(shí)間,Android采用了一個(gè)叫Recycler的組件。

工作原理:當(dāng)屏幕需要顯示x個(gè)item時(shí),那么ListView只會(huì)創(chuàng)建x+1個(gè)視圖,當(dāng)?shù)谝粋€(gè)item離開屏幕時(shí),此item的view就會(huì)被拿來重用(用于顯示下一個(gè)item(即第x+1個(gè))的內(nèi)容)。

工作原理實(shí)例

假如屏幕只能顯示7個(gè)item,那么ListView只會(huì)創(chuàng)建(7+1)個(gè)item的視圖。當(dāng)?shù)?個(gè)item離開屏幕時(shí),此item的view就會(huì)被拿來重用(用于顯示第8個(gè)item的內(nèi)容)。原理如下圖顯示

ListView的使用

1. 生成方式

生成列表視圖(ListView)的方式主要有兩種:

  • 直接用ListView進(jìn)行創(chuàng)建
  • 讓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的常用屬性和相關(guān)方法

屬性說明備注
android:choiceMode列表的選擇行為,默認(rèn):none沒有選擇行為選擇方式: none:不顯示任何選中項(xiàng) singleChoice:允許單選multipleChoice:允許多選multipleChoiceModal:允許多選 (把Activity里面adapter的第二個(gè)參數(shù)改成支持選擇的布局)
android:drawSelectorOnTop如果該屬性設(shè)置為true,選中的列表項(xiàng)將會(huì)顯示在上面
android:listSelector為點(diǎn)擊到的Item設(shè)置圖片如果該屬性設(shè)置為true,選中的列表項(xiàng)將會(huì)顯示在上面
android:fastScrollEnabled設(shè)置是否允許快速滾動(dòng)如果該屬性設(shè)置為true,將會(huì)顯示滾動(dòng)圖標(biāo),并允許用戶拖動(dòng)該滾動(dòng)圖標(biāo)進(jìn)行快速滾動(dòng)。
android:listSelector指定被選中的列表項(xiàng)上繪制的Drawable
android:scrollingCache滾動(dòng)時(shí)是否使用緩存如果設(shè)置為true,則在滾動(dòng)時(shí)將會(huì)使用緩存
android:stackFromBottom設(shè)置是否從底端開始排列列表項(xiàng)
android:transcriptMode指定列表添加新的選項(xiàng)的時(shí)候,是否自動(dòng)滑動(dòng)到底部,顯示新的選項(xiàng)。disabled:取消transcriptMode模式;默認(rèn)的normal:當(dāng)接受到數(shù)據(jù)集合改變的通知,并且僅僅當(dāng)最后一個(gè)選項(xiàng)已經(jīng)顯示在屏幕的時(shí)候,自動(dòng)滑動(dòng)到底部。 alwaysScroll:無論當(dāng)前列表顯示什么選項(xiàng),列表將會(huì)自動(dòng)滑動(dòng)到底部顯示最新的選項(xiàng)。

Listview提供的XML屬性:

XML屬性說明備注
android:divider設(shè)置List列表項(xiàng)的分隔條(可用顏色分割,也可用圖片(Drawable)分割不設(shè)置列表之間的分割線,可設(shè)置屬性為@null
android:dividerHeight用于設(shè)置分隔條的高度
android:background屬性設(shè)置列表的背景
android:entries指定一個(gè)數(shù)組資源,Android將根據(jù)該數(shù)組資源來生成ListView
android:footerDividerEnabled如果設(shè)置成false,則不在footer View之前繪制分隔條
andorid:headerDividerEnabled如果設(shè)置成false,則不再header View之前繪制分隔條

Adapter介紹

Adapter本身是一個(gè)接口,Adapter接口及其子類的繼承關(guān)系如下圖:

Adapter接口派生了ListAdapter和SpinnerAdapter兩個(gè)子接口

其中ListAdapter為AbsAdapter提供列表項(xiàng),而SpinnerAdapter為AbsSpinner提供列表項(xiàng)

ArrayAdapter、SimpleAdapter、SimpleCursorAdapter、BaseAdapter都是常用的實(shí)現(xiàn)適配器的類

  • ArrayAdapter:簡單、易用的Adapter,用于將數(shù)組綁定為列表項(xiàng)的數(shù)據(jù)源,支持泛型操作

  • SimpleAdapter:功能強(qiáng)大的Adapter,用于將XML中控件綁定為列表項(xiàng)的數(shù)據(jù)源

  • SimpleCursorAdapter:與SimpleAdapter類似,用于綁定游標(biāo)(直接從數(shù)據(jù)數(shù)取出數(shù)據(jù))作為列表項(xiàng)的數(shù)據(jù)源

  • BaseAdapter:可自定義ListView,通用用于被擴(kuò)展。擴(kuò)展BaseAdapter可以對各個(gè)列表項(xiàng)進(jìn)行最大程度的定制。

常用適配器介紹

1. ArrayAdapter

定義:簡單、易用的Adapter,用于將數(shù)組綁定為列表項(xiàng)的數(shù)據(jù)源,支持泛型操作

步驟

1、 在xml文件布局上實(shí)現(xiàn)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上定義一個(gè)鏈表,將所要展示的數(shù)據(jù)以存放在里面
3、 構(gòu)造ArrayAdapter對象,設(shè)置適配器
4、 將LsitView綁定到ArrayAdapter上

public class MainActivity extends AppCompatActivity { @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListView listView = (ListView) findViewById(R.id.list_item);//定義一個(gè)鏈表用于存放要顯示的數(shù)據(jù)final List<String> adapterData = new ArrayList<String>();//存放要顯示的數(shù)據(jù)for (int i = 0; i < 20; i++) {adapterData.add("ListItem" + i);}//創(chuàng)建ArrayAdapter對象adapter并設(shè)置適配器ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, adapterData);//將LsitView綁定到ArrayAdapter上listView.setAdapter(adapter);} }

創(chuàng)建ArrayAdapter對象要指定三個(gè)參數(shù):

  • context:代表方位Android應(yīng)用的接口
  • textViewRseourceld:資源ID,代表一個(gè)TextView
  • 數(shù)組:列表項(xiàng)展示的數(shù)據(jù)

5、 在xml文件布局添加資源文件TextView,該TextView組件將作列表項(xiàng)的組件

<?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>

最終效果圖

缺點(diǎn):ArrayAdapter較為簡單,易用,但每個(gè)列表項(xiàng)只能是TextView,功能實(shí)現(xiàn)的局限性非常大。

2. SimpleAdapter

定義:功能強(qiáng)大的Adapter,用于將XML中控件綁定作為列表項(xiàng)的數(shù)據(jù)源

特點(diǎn):可對每個(gè)列表項(xiàng)進(jìn)行定制(自定義布局),能滿足大多數(shù)開發(fā)的需求場景,靈活性較大

步驟
1、 在xml文件布局上實(shí)現(xiàn)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、 根據(jù)實(shí)際需求定制列表項(xiàng):實(shí)現(xiàn)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、 定義一個(gè)HashMap構(gòu)成的列表以鍵值對的方式存放數(shù)據(jù)
4、 構(gòu)造SimpleAdapter對象,設(shè)置適配器
5、 將LsitView綁定到SimpleAdapter上

public class MainActivity extends AppCompatActivity {//定義數(shù)組以填充數(shù)據(jù)private String[] name=new String[]{"威龍注塑機(jī)","霸龍注塑機(jī)","恐龍注塑機(jī)" };private String[] address =new String[]{"廣東","北京","黑龍江" };private int[] lowerest_wholesale =new int[]{11,22,33 };private int[] price =new int[]{11,22,33 };private int[] picture =new int[]{R.drawable.home_selected,R.drawable.home_selected,R.drawable.home_selected };@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//定義一個(gè)HashMap構(gòu)成的列表以鍵值對的方式存放數(shù)據(jù)ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String,Object>>();//循環(huán)填充數(shù)據(jù) for(int i=0;i<name.length;i++) {HashMap<String,Object> map = new HashMap<String,Object>();map.put("name", name[i]);map.put("address", address[i]);map.put("lowerest_wholesale", lowerest_wholesale[i]);map.put("price", price[i]);map.put("picture", picture[i]);listItem.add(map);}//構(gòu)造SimpleAdapter對象,設(shè)置適配器 SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,listItem,//需要綁定的數(shù)據(jù) R.layout.item_imformation,//每一行的布局 new String[] {"name","address", "lowerest_wholesale","price","picture"},//數(shù)組中的數(shù)據(jù)源的鍵對應(yīng)到定義布局的View中 new int[] {R.id.name,R.id.address,R.id.lowerest_wholesale,R.id.price,R.id.picture});ListView list= (ListView) findViewById(R.id.list_item);//為ListView綁定適配器 list.setAdapter(mSimpleAdapter);}}

結(jié)果顯示

BaseAdapter

定義:可自定義ListView,通用用于被擴(kuò)展。擴(kuò)展BaseAdapter可以對各個(gè)列表項(xiàng)進(jìn)行最大程度的定制

使用步驟:

  • 定義主xml布局
  • 根據(jù)需要定義ListView每行所實(shí)現(xiàn)的xml布局
  • 定義一個(gè)Adapter類繼承BaseAdapter,重寫里面的方法。
  • 定義一個(gè)HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對的方式存放在里面。
  • 構(gòu)造Adapter對象,設(shè)置適配器。
  • 將LsitView綁定到Adapter上。

先定義一個(gè)Adapter類繼承BaseAdapter,并重寫里面的方法

使用BaseAdapter必須寫一個(gè)類繼承它,同時(shí)BaseAdapter是一個(gè)抽象類,繼承它必須實(shí)現(xiàn)它的方法。

class MyAdapter extends BaseAdapter {private LayoutInflater mInflater;//得到一個(gè)LayoutInfalter對象用來導(dǎo)入布局//構(gòu)造函數(shù)public MyAdapter(Context context,ArrayList<HashMap<String, Object>> listItem) {this.mInflater = LayoutInflater.from(context);this.listItem = listItem;}//聲明構(gòu)造函數(shù)@Overridepublic int getCount() {return listItem.size();}//這個(gè)方法返回了在適配器中所代表的數(shù)據(jù)集合的條目數(shù)@Overridepublic Object getItem(int position) {return listItem.get(position);}//這個(gè)方法返回了數(shù)據(jù)集合中與指定索引position對應(yīng)的數(shù)據(jù)項(xiàng)@Overridepublic long getItemId(int position) {return position;}//這個(gè)方法返回了在列表中與指定索引對應(yīng)的行id@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return null;}//這個(gè)方法返回了指定索引對應(yīng)的數(shù)據(jù)項(xiàng)的視圖,還沒寫完 }

這里主要講一下BaseAdapter里必須要重寫的4個(gè)方法

  • BaseAdapter的靈活性就在于它要重寫很多方法,其中最重要的即為getView()方法。
  • 我們結(jié)合上述重寫的4個(gè)方法了解下系統(tǒng)繪制ListView的原理:

當(dāng)系統(tǒng)開始繪制ListView的時(shí)候,首先調(diào)用getCount()方法。得到它的返回值,即ListView的長度。

系統(tǒng)調(diào)用getView()方法,根據(jù)這個(gè)長度逐一繪制ListView的每一行。(如果讓getCount()返回1,那么只顯示一行)。

getItem()和getItemId()則在需要處理和取得Adapter中的數(shù)據(jù)時(shí)調(diào)用。

那么getView()如何使用呢?如果有10000行數(shù)據(jù),就繪制10000次?這肯定會(huì)極大的消耗資源,導(dǎo)致ListView滑動(dòng)非常的慢,那應(yīng)該怎么做呢?可以使用BaseAdapter進(jìn)行優(yōu)化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;}//這個(gè)方法返回了指定索引對應(yīng)的數(shù)據(jù)項(xiàng)的視圖

這種方法每次getView()都要findViewById和重新繪制一個(gè)View,當(dāng)列表項(xiàng)數(shù)據(jù)量很大的時(shí)候會(huì)嚴(yán)重影響性能,造成下拉很慢,所以數(shù)據(jù)量大的時(shí)候不推薦用這種方式。

重寫getView()的第二種方法:使用convertView作為緩存進(jìn)行優(yōu)化
getView()返回值是一個(gè)View,把它作為輸入?yún)?shù)并放到getView()輸入?yún)?shù)里,形成反饋。這樣就形成了Adapter的itemView重用機(jī)制,減少了重繪View的次數(shù)。

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if(convertView == null){convertView = mInflater.inflate(R.layout.item, null);}//檢測有沒有可以重用的View,沒有就重新繪制ImageView img = (ImageView)convertView.findViewById(R.id.ItemImage);TextView title = (TextView)convertView.findViewById(R.id.ItemTitle);TextView test = (TextView)convertView.findViewById(R.id.ItemText);Button btn = (Button) convertView.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 convertView;}//這個(gè)方法返回了指定索引對應(yīng)的數(shù)據(jù)項(xiàng)的視圖

這種方法和第一種相比減少了重繪View的次數(shù),但是還是每一次都要findViewById

重寫getView()第三種方法

通過convertView+ViewHolder來實(shí)現(xiàn)緩存進(jìn)而進(jìn)行優(yōu)化
convertView緩存了View,ViewHolder相當(dāng)于更加具體的緩存:View里的組件,即把View和View的組件一并進(jìn)行緩存,那么重用View的時(shí)候就不用再重繪View和View的組件(findViewById)

static class ViewHolder{public ImageView img;public TextView title;public TextView text;public Button btn;}//聲明一個(gè)外部靜態(tài)類@Overridepublic View getView(int position, View convertView, 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"));return convertView;}//這個(gè)方法返回了指定索引對應(yīng)的數(shù)據(jù)項(xiàng)的視圖

這種方法就既減少了重繪View,又減少了findViewById的次數(shù),所以這種方法是最能節(jié)省資源的,所以非常推薦大家使用通過convertView+ViewHolder來重寫getView()

利用convertView+ViewHolder來重寫getView()的實(shí)現(xiàn)BaseAdapter的具體實(shí)現(xiàn)代碼:

定義主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>

根據(jù)需要,定義ListView每行所實(shí)現(xiàn)的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>

定義一個(gè)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;//得到一個(gè)LayoutInfalter對象用來導(dǎo)入布局 ArrayList<HashMap<String, Object>> listItem;public MyAdapter(Context context,ArrayList<HashMap<String, Object>> listItem) {this.mInflater = LayoutInflater.from(context);this.listItem = listItem;}//聲明構(gòu)造函數(shù)@Overridepublic int getCount() {return listItem.size();}//這個(gè)方法返回了在適配器中所代表的數(shù)據(jù)集合的條目數(shù)@Overridepublic Object getItem(int position) {return listItem.get(position);}//這個(gè)方法返回了數(shù)據(jù)集合中與指定索引position對應(yīng)的數(shù)據(jù)項(xiàng)@Overridepublic long getItemId(int position) {return position;}//這個(gè)方法返回了在列表中與指定索引對應(yīng)的行id//利用convertView+ViewHolder來重寫getView()static class ViewHolder{public ImageView img;public TextView title;public TextView text;public Button btn;}//聲明一個(gè)外部靜態(tài)類@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("你點(diǎn)擊了選項(xiàng)"+position);//bottom會(huì)覆蓋item的焦點(diǎn),所以要在xml里面配置android:focusable="false"}});return convertView;}//這個(gè)方法返回了指定索引對應(yīng)的數(shù)據(jù)項(xiàng)的視圖 }

4、在MainActivity里:

  • 定義一個(gè)HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對的方式存放在里面。
  • 構(gòu)造Adapter對象,設(shè)置適配器。
  • 將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);/*定義一個(gè)以HashMap為內(nèi)容的動(dòng)態(tài)數(shù)組*/ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();/*在數(shù)組中存放數(shù)據(jù)*/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("你點(diǎn)擊了第" + arg2 + "行");//設(shè)置系統(tǒng)輸出點(diǎn)擊的行}});} }

運(yùn)行結(jié)果

點(diǎn)擊輸出結(jié)果:

RecyclerView介紹

1. 定義

RecyclerView是Google推出用來代替ListView組件的,是一個(gè)強(qiáng)大的滑動(dòng)組件。
RecyclerView強(qiáng)制使用了ViewHolder,直接把viewholder的實(shí)現(xiàn)封裝起來,用戶只要實(shí)現(xiàn)自己的viewholder就可以了,該組件會(huì)自動(dòng)幫你回收復(fù)用每一個(gè)item。

2. 工作原理

當(dāng)屏幕需要顯示x個(gè)item時(shí),那么ListView只會(huì)創(chuàng)建x+1個(gè)視圖,當(dāng)?shù)谝粋€(gè)item離開屏幕時(shí),此item的view就會(huì)被拿來重用(用于顯示下一個(gè)item(即第x+1個(gè))的內(nèi)容)。

3. 工作原理實(shí)例

假如屏幕只能顯示7個(gè)item,那么ListView只會(huì)創(chuàng)建(7+1)個(gè)item的視圖。當(dāng)?shù)?個(gè)item離開屏幕時(shí),此item的view就會(huì)被拿來重用(用于顯示第8個(gè)item的內(nèi)容)。原理如下圖顯示

4. RecyclerView的重要概念介紹

RecyclerView.Adapter

和ListView一樣,RecyclerView一樣需要適配器,而且這個(gè)適配器強(qiáng)制要求了我們必須要用Viewholder,讓性能得到優(yōu)化,而且getView方法不需自己寫,我們只需要寫好Viewholder,View的復(fù)用已經(jīng)封裝好了。

LayoutManager

管理布局,設(shè)置為LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager可以輕易地實(shí)現(xiàn)ListView,GridView以及流式布局的列表效果。它還可以管理滾動(dòng)和循環(huán)利用。

ItemAnimator

這個(gè)類可以實(shí)現(xiàn)增刪動(dòng)畫,而且不想設(shè)置的話它的默認(rèn)效果已經(jīng)很好了。

5. 優(yōu)缺點(diǎn)

優(yōu)點(diǎn) : 有了ListView、GridView為什么還需要RecyclerView這樣的控件呢?優(yōu)點(diǎn)在于

  • item復(fù)用性高
    把ViewHolder的實(shí)現(xiàn)封裝起來,規(guī)范了ViewHolder,把item的view寫入ViewHolder中,可以通過復(fù)用ViewHolder來實(shí)現(xiàn)view的復(fù)用
  • 靈活、可定制化高、可拓展性高
    整體上看RecyclerView架構(gòu),提供了一種插拔式的體驗(yàn):高度的解耦,異常的靈活:
  • 控制其顯示的方式-通過布局管理器LayoutManager
  • 控制Item間的間隔(可繪制)-通過ItemDecoration
  • 控制Item增刪的動(dòng)畫- 通過ItemAnimator
mRecyclerView = findView(R.id.id_recyclerview); //設(shè)置布局管理器 mRecyclerView.setLayoutManager(layout); //設(shè)置adapter mRecyclerView.setAdapter(adapter) //設(shè)置Item增加、移除動(dòng)畫 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); //添加分割線 mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

問:相比較于ListView,RecyclerView基本需要上面一系列步驟進(jìn)行設(shè)置,而ListView可能只需要去設(shè)置一個(gè)adapter就能正常使用。那么為什么會(huì)添加這么多的步驟呢?

答:從名字上看RecyclerView,即回收循環(huán)視圖,也就是說RecyclerView只管回收與復(fù)用View,其他的你可以自己去設(shè)置,可以看出其高度的解耦,給予你充分的定制自由

缺點(diǎn): RecyclerView實(shí)現(xiàn)控制點(diǎn)擊、長按事件較為麻煩,需要自己寫

使用實(shí)例

使用RecyclerView的步驟:

  • 定義主xml布局
  • 根據(jù)需要定義RecyclerView每行所實(shí)現(xiàn)的xml布局
  • 定義一個(gè)Adapter類繼承RecyclerView.Adapter,重寫里面的方法。
  • 定義一個(gè)HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對的方式存放在里面。
  • 構(gòu)造Adapter對象,設(shè)置適配器。
  • 將RecyclerView綁定到Adapter上。

Demo的源碼下載:https://github.com/Carson-Ho/RecyclerView

個(gè)人推薦先fork下來再對著下面的分析看,效果會(huì)更好哦!

步驟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"/><!--設(shè)置一個(gè)RecyclerView--></RelativeLayout>

在AndroidStudio1.5使用support-v7包:

  • 右鍵文件目錄的app目錄進(jìn)入Moudle Setting
  • 在Dependencies里面加入com.android.support:recyclerview-v7:23.1.1包。

步驟2. 根據(jù)需要定義RecyclerView每行所實(shí)現(xiàn)的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. 定義一個(gè)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;}//構(gòu)造函數(shù),傳入數(shù)據(jù)//定義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());}}//監(jiān)聽到點(diǎn)擊就回調(diào)MainActivity的onItemClick函數(shù));}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"));}//在這里綁定數(shù)據(jù)到ViewHolder里面@Overridepublic int getItemCount() {return listItem.size();}//返回Item數(shù)目public void setOnItemClickListener(MyItemClickListener listener){myItemClickListener = listener;}//綁定MainActivity傳進(jìn)來的點(diǎn)擊監(jiān)聽器 }

實(shí)現(xiàn)點(diǎn)擊事件:

  • 在Viewholder里面設(shè)置了點(diǎn)擊事件監(jiān)聽器
  • 通過調(diào)用OnItemClickListener的接口方法回調(diào)MainActivity里的方法。
  • MyItemClickListener.java接口:用來實(shí)現(xiàn)點(diǎn)擊事件

    package scut.receiverview;import android.view.View;public interface MyItemClickListener {public void onItemClick(View view,int postion); }

    步驟4:在MainActicity.java里:

    • 定義一個(gè)HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對的方式存放在里面。
    • 構(gòu)造Adapter對象,設(shè)置適配器
    • 將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>>();/*在數(shù)組中存放數(shù)據(jù)*/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()));//用類設(shè)置分割線 //Rv.addItemDecoration(new DividerItemDecoration(this, R.drawable.list_divider)); //用已有圖片設(shè)置分割線}@Overridepublic void onItemClick(View view, int postion) {//點(diǎn)擊事件的回調(diào)函數(shù)System.out.println("點(diǎn)擊了第"+postion+"行");Toast.makeText(this, (String)listItem.get(postion).get("ItemText"), Toast.LENGTH_SHORT).show();}}
  • 最后是一個(gè)步驟是實(shí)現(xiàn)分割線ItemDecoration
  • 如果自己畫了分割線就可以直接添上去,不需要寫這個(gè)類

    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的布局方向,默認(rèn)先賦值* 為縱向布局* RecyclerView 布局可橫向,也可縱向* 橫向和縱向?qū)?yīng)的分割想畫法不一樣* */private int mOrientation = LinearLayoutManager.VERTICAL ;/*** item之間分割線的size,默認(rèn)為1*/private int mItemSize = 1 ;/*** 繪制item分割線的畫筆,和設(shè)置其屬性* 來繪制個(gè)性分割線*/private Paint mPaint ;/*** 構(gòu)造方法傳入布局方向,不可不傳* @param context* @param orientation*/public DividerItemDecoration(Context context,int orientation) {this.mOrientation = orientation;if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){throw new IllegalArgumentException("請傳入正確的參數(shù)") ;}mItemSize = (int) TypedValue.applyDimension(mItemSize, TypedValue.COMPLEX_UNIT_DIP,context.getResources().getDisplayMetrics());mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ;mPaint.setColor(Color.BLUE);/*設(shè)置填充*/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);}}/*** 設(shè)置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);}} }

    效果輸出圖

    總結(jié)

    本文對ListView、AdapterView、RecyclerView進(jìn)行了全面整理,接下來我會(huì)介紹繼續(xù)介紹Android開發(fā)中的相關(guān)知識(shí),有興趣可以繼續(xù)關(guān)注Carson_Ho的安卓開發(fā)筆記

    總結(jié)

    以上是生活随笔為你收集整理的ListView、AdapterView、RecyclerView全面解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。