Carson帶你學(xué)Android:ListView與AdapterView全面解析

前言

  • ListViewAndroid開發(fā)中十分常見
  • 今天,我將為大家?guī)?lái)ListViewAdapterView全面解析,含其特點(diǎn)、工作原理等,希望你們會(huì)喜歡。

目錄

示意圖

1. 簡(jiǎn)介

  • Android中的一種列表視圖組件
  • 繼承自AdapterView抽象類,類圖關(guān)系如下
示意圖

2. 作用

集合多個(gè) “項(xiàng)”(稱為:Item) & 以列表的形式 展示

示意圖

3. 工作原理

3.1 本質(zhì)原理

  • ListView僅作為容器(列表),用于裝載 & 顯示數(shù)據(jù)(即 列表項(xiàng)Item
  • 而容器內(nèi)的具體數(shù)據(jù)(列表項(xiàng)Item)則是由 適配器(Adapter)提供

適配器(Adapter):作為View 和 數(shù)據(jù)之間的橋梁 & 中介,將數(shù)據(jù)映射到要展示的View

  • 當(dāng)需顯示數(shù)據(jù)時(shí),ListView會(huì)向Adapter取出數(shù)據(jù),從而加載顯示,具體如下圖
示意圖
  • 結(jié)論
    ListView負(fù)責(zé)以列表的形式顯示Adapter提供的內(nèi)容

3.2 緩存原理

試想一個(gè)場(chǎng)景:若把所有數(shù)據(jù)集合的信息都加載到ListView上顯示,若 ListView要為每個(gè)數(shù)據(jù)都創(chuàng)建一個(gè)視圖,那么會(huì)占用非常多的內(nèi)存

  • 為了節(jié)省空間和時(shí)間,ListView不會(huì)為每一個(gè)數(shù)據(jù)創(chuàng)建一個(gè)視圖,而是采用了Recycler組件,用于回收 & 復(fù)用 View

  • 當(dāng)屏幕需顯示x個(gè)Item時(shí),那么ListView會(huì)創(chuàng)建 x+1個(gè)視圖;當(dāng)?shù)?個(gè)Item離開屏幕時(shí),此ItemView被回收至緩存,入屏的ItemView會(huì)優(yōu)先從該緩存中獲取

注:

  1. 只有Item完全離開屏幕后才可復(fù)用,這也是為什么ListView要?jiǎng)?chuàng)建比屏幕需顯示視圖多1個(gè)的原因:緩沖 顯示視圖
  2. 即:第1個(gè)Item離開屏幕是有過(guò)程的,會(huì)有1個(gè) 第1個(gè)Item的下半部分 & 第8個(gè)Item上半部分同時(shí)在屏幕中顯示的狀態(tài),此時(shí)仍無(wú)法使用緩存的View,只能繼續(xù)用新創(chuàng)建的視圖View
  • 實(shí)例演示
    設(shè):屏幕只能顯示5個(gè)Item,那么ListView只會(huì)創(chuàng)建(5+1)個(gè)Item的視圖;當(dāng)?shù)?個(gè)Item完全離開屏幕后才會(huì)回收至緩存從而復(fù)用(用于顯示第7個(gè)Item
示意圖

4. 具體使用

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)方法:

屬性 說(shuō)明 備注
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:無(wú)論當(dāng)前列表顯示什么選項(xiàng),列表將會(huì)自動(dòng)滑動(dòng)到底部顯示最新的選項(xiàng)。

Listview提供的XML屬性:

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

5. Adapter簡(jiǎn)介

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

Adapter接口及其子類的繼承關(guān)系.png
  • Adapter接口派生了ListAdapter和SpinnerAdapter兩個(gè)子接口

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

  • ArrayAdapter、SimpleAdapter、SimpleCursorAdapter、BaseAdapter都是常用的實(shí)現(xiàn)適配器的類
  1. ArrayAdapter:簡(jiǎn)單、易用的Adapter,用于將數(shù)組綁定為列表項(xiàng)的數(shù)據(jù)源,支持泛型操作
  2. SimpleAdapter:功能強(qiáng)大的Adapter,用于將XML中控件綁定為列表項(xiàng)的數(shù)據(jù)源
  3. SimpleCursorAdapter:與SimpleAdapter類似,用于綁定游標(biāo)(直接從數(shù)據(jù)數(shù)取出數(shù)據(jù))作為列表項(xiàng)的數(shù)據(jù)源
  4. BaseAdapter:可自定義ListView,通用用于被擴(kuò)展。擴(kuò)展BaseAdapter可以對(duì)各個(gè)列表項(xiàng)進(jìn)行最大程度的定制。

6. 常用適配器介紹

6.1 ArrayAdapter

定義
簡(jiǎn)單、易用的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>
效果圖.png

2. 在MainActivity上定義一個(gè)鏈表,將所要展示的數(shù)據(jù)以存放在里面
3. 構(gòu)造ArrayAdapter對(duì)象,設(shè)置適配器
4. 將LsitView綁定到ArrayAdapter上
如下圖:

public class MainActivity extends AppCompatActivity {     


    @Override
    protected 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對(duì)象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對(duì)象要指定三個(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>

最終效果圖

最終效果圖.png

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

6.2 SimpleAdapter

  • 定義:功能強(qiáng)大的Adapter,用于將XML中控件綁定作為列表項(xiàng)的數(shù)據(jù)源
  • 特點(diǎn):可對(duì)每個(gè)列表項(xiàng)進(jìn)行定制(自定義布局),能滿足大多數(shù)開發(fā)的需求場(chǎng)景,靈活性較大

步驟
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:textSize="17sp"            
android:paddingLeft="14dp"/>        
<TextView            
android:id="@+id/address"            
android:layout_below="@id/name"            
android:textSize="17sp"            
android:layout_width="wrap_content"            
android:layout_height="wrap_content" />        
<TextView            
android:id="@+id/lowerest_wholesale"            
android:layout_toRightOf="@id/address"            
android:textSize="17sp"            
android:layout_width="wrap_content"            
android:layout_height="wrap_content" />        
<TextView            
android:id="@+id/price"            
android:textSize="17sp"            
android:layout_below="@id/address"            
android:layout_width="wrap_content"            
android:layout_height="wrap_content" />        
<ImageView            
android:id="@+id/picture"            
android:layout_alignParentRight="true"            
android:layout_width="115dp"            
android:layout_height="86dp"         />        
</RelativeLayout>

3. 定義一個(gè)HashMap構(gòu)成的列表以鍵值對(duì)的方式存放數(shù)據(jù)
4. 構(gòu)造SimpleAdapter對(duì)象,設(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   };    

@Override    
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);   
         setContentView(R.layout.activity_main);

//定義一個(gè)HashMap構(gòu)成的列表以鍵值對(duì)的方式存放數(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對(duì)象,設(shè)置適配器        
SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,
listItem,//需要綁定的數(shù)據(jù)                
R.layout.item_imformation,//每一行的布局                
new String[] {"name","address", "lowerest_wholesale","price","picture"},
//數(shù)組中的數(shù)據(jù)源的鍵對(duì)應(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);        
//為L(zhǎng)istView綁定適配器        
list.setAdapter(mSimpleAdapter);   
   }
}

結(jié)果顯示

結(jié)果顯示

6.3 BaseAdapter

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

使用步驟:

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

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

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

class MyAdapter extends BaseAdapter {
    private LayoutInflater mInflater;//得到一個(gè)LayoutInfalter對(duì)象用來(lái)導(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ù)

    @Override
    public int getCount() {
        return listItem.size();
    }//這個(gè)方法返回了在適配器中所代表的數(shù)據(jù)集合的條目數(shù)

    @Override
    public Object getItem(int position) {
        return listItem.get(position);
    }//這個(gè)方法返回了數(shù)據(jù)集合中與指定索引position對(duì)應(yīng)的數(shù)據(jù)項(xiàng)

    @Override
    public long getItemId(int position) {
        return position;
    }//這個(gè)方法返回了在列表中與指定索引對(duì)應(yīng)的行id


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return null;
    }//這個(gè)方法返回了指定索引對(duì)應(yīng)的數(shù)據(jù)項(xiàng)的視圖,還沒寫完
}

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

  • BaseAdapter的靈活性就在于它要重寫很多方法,其中最重要的即為getView()方法。
  • 我們結(jié)合上述重寫的4個(gè)方法了解ListView的繪制過(guò)程:
示意圖

其中,重點(diǎn)講解重寫的getView()方式,總共有3種


/**
  * 重寫方式1:直接返回了指定索引對(duì)應(yīng)的數(shù)據(jù)項(xiàng)的視圖
  */
    @Override
    public 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;
    }
    // 缺點(diǎn):
    // 每次調(diào)用getView()時(shí),都要重新通過(guò) findViewById() 尋找View組件 & 重新繪制View
    // 當(dāng)列表項(xiàng)數(shù)據(jù)量很大時(shí)會(huì)嚴(yán)重影響性能,即體現(xiàn)為下拉很慢、卡

/**
  * 重寫方式2:使用convertView作為View緩存(優(yōu)化)
  * 具體原理:
  *       // a. 將 convertView作為getView()的輸入?yún)?shù) & 返回參數(shù),從而形成反饋
  *       // b. 形成了Adapter的itemView重用機(jī)制,減少了重繪View的次數(shù)
  */
     @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // 檢測(cè)有無(wú)可重用的View,若無(wú)就重新繪制
        if(convertView == null)
        {
            convertView = mInflater.inflate(R.layout.item, null);
        }
        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;
        // 最終返回convertView形成反饋
    }

    // 優(yōu)點(diǎn):減少了重繪View的次數(shù)
    // 缺點(diǎn):但是每次都要通過(guò) findViewById() 尋找View組件

/**
  * 重寫方式3:在方式2的基礎(chǔ)上,使用ViewHolder實(shí)現(xiàn)更加具體的緩存:View組件緩存
  * 具體原理:
  *       // a. 將 convertView作為getView()的輸入?yún)?shù) & 返回參數(shù),從而形成反饋
  *       // b. 形成了Adapter的itemView重用機(jī)制,減少了重繪View的次數(shù)
  */
    static class ViewHolder

        {
            public ImageView img;
            public TextView title;
            public TextView text;
            public Button btn;
        }

    @Override
        public 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;
        }
  // 優(yōu)點(diǎn):重用View時(shí)就不用通過(guò) findViewById()重新 尋找View組件,同時(shí)也減少了重繪View的次數(shù),是ListView使用的最優(yōu)化方案
  • 方案3(通過(guò)convertView+ViewHolder重寫getView())是ListView使用的最優(yōu)化,所以非常推薦大家使用

  • 總結(jié):ListView的優(yōu)化

示意圖
  • 最優(yōu)化方案的完整實(shí)現(xiàn)方案
  1. 定義主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>
  1. 根據(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>
  1. 定義一個(gè)Adapter類繼承BaseAdapter,重寫里面的方法。

(利用convertView+ViewHolder來(lái)重寫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;

class MyAdapter extends BaseAdapter {
    private LayoutInflater mInflater;//得到一個(gè)LayoutInfalter對(duì)象用來(lái)導(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ù)

    @Override
    public int getCount() {
        return listItem.size();
    }//這個(gè)方法返回了在適配器中所代表的數(shù)據(jù)集合的條目數(shù)

    @Override
    public Object getItem(int position) {
        return listItem.get(position);
    }//這個(gè)方法返回了數(shù)據(jù)集合中與指定索引position對(duì)應(yīng)的數(shù)據(jù)項(xiàng)

    @Override
    public long getItemId(int position) {
        return position;
    }//這個(gè)方法返回了在列表中與指定索引對(duì)應(yīng)的行id

//利用convertView+ViewHolder來(lái)重寫getView()
    static class ViewHolder
    {
        public ImageView img;
        public TextView title;
        public TextView text;
        public Button btn;
    }//聲明一個(gè)外部靜態(tài)類
    @Override
    public 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() {
            @Override
            public void onClick(View v) {
                System.out.println("你點(diǎn)擊了選項(xiàng)"+position);//bottom會(huì)覆蓋item的焦點(diǎn),所以要在xml里面配置android:focusable="false"
            }
        });

        return convertView;
    }//這個(gè)方法返回了指定索引對(duì)應(yīng)的數(shù)據(jù)項(xiàng)的視圖
}

4.在MainActivity里:

  • 定義一個(gè)HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對(duì)的方式存放在里面。
  • 構(gòu)造Adapter對(duì)象,設(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;

    @Override
    public 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);//為L(zhǎng)istView綁定適配器

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public 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é)果:



注:進(jìn)階使用 = 添加頭部 & 尾部View

在日常使用中,我們常常會(huì)需要在ListView頭部 / 尾部添加視圖

步驟1:添加頭部 / 尾部視圖

header_view.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="70dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="header"
        android:textSize="20dp"
        android:gravity="center"/>

</LinearLayout>

步驟2:添加到ListView中

private ListView lv;

View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.header_view, null);

lv.addHeaderView(view);
// lv.addFooterView(view); // 添加到底部View

示意圖


7. 與RecylerView的區(qū)別

image.png

8. 總結(jié)

  • 本文全面介紹了 ListViewAdapterView
  • 下面我將繼續(xù)對(duì) Android中的知識(shí)進(jìn)行深入講解 ,感興趣的同學(xué)可以繼續(xù)關(guān)注Carson_Ho的簡(jiǎn)書

相關(guān)系列文章閱讀
Carson帶你學(xué)Android:學(xué)習(xí)方法
Carson帶你學(xué)Android:四大組件
Carson帶你學(xué)Android:自定義View
Carson帶你學(xué)Android:異步-多線程
Carson帶你學(xué)Android:性能優(yōu)化
Carson帶你學(xué)Android:動(dòng)畫


歡迎關(guān)注Carson_Ho的簡(jiǎn)書

不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度


請(qǐng)點(diǎn)贊!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容