天天看點

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

目錄

前言

相關屬性及方法

設定分割線

設定表頭表尾

ArrayAdapter示例

SimpleAdapter示例

BaseAdapter示例

2019.9.4 新增補充:

設定分割線及表頭表尾部分

使用的 Demo 是 BaseAdapter示例 ,如果看不懂可以 先過下屬性和方法,等看到 BaseAdapter 再回來看例程

放心,我會放傳送門的!

前言

ListView 在 Android 衆多控件中占有比較重要的地位,通常用于顯示垂直滾動列。

Google 在釋出的 v7相容包 中提出了新的控件RecyclerView,可代替ListView。這個後面再學,先搞定ListView,畢竟内容也不少,一步步慢慢來。

一個ListView通常都有三個要素組成:

  • ListView控件
  • 擴充卡類,用到了設計模式中的擴充卡模式,它是視圖和資料之間的橋梁,負責提供對資料的通路,生成每一個清單項對于的View。
  • 資料源,當然最重要最複雜的部分就是擴充卡類的編寫和設計,在一些複雜的界面,常常需要對擴充卡類進行相關邏輯處理。

相關屬性及方法

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

設定分割線

相關屬性

footerDividersEnabled        是否在footerView(表尾)前繪制一個分隔條,預設為true

headerDividersEnabled      是否在headerView(表尾)前繪制一個分隔條,預設為true

divider                                  設定分隔條,可以用顔色分割,也可以用drawable資源分割

dividerHeigh                        設定分隔條的高度

示例

在 BaseAdapter示例 的基礎上,修改 activity_list_view.xml,給 ListView 添加屬性即可

<?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:orientation="vertical"
    tools:context=".ListViewActivity"
    android:padding="10dp">

    <ListView
        android:id="@+id/id_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#8888"
        android:dividerHeight="5dp">
    </ListView>


</LinearLayout>
           

效果圖

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

設定表頭表尾

相關java方法

addHeaderView(View v)                                     添加headView(表頭),括号中的參數是一個View對象

addFooterView(View v)                                      添加footerView(表尾),括号中的參數是一個View對象

addHeaderView(headView, null, false)             和前面的差別:設定Header是否可以被選中

addFooterView(View,view,false)                       同上

示例

在 BaseAdapter示例 的基礎上,添加表頭表尾xml

activity_listview_header.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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:text="表頭"
        android:textSize="18sp"
        android:textAlignment="center"
        android:textColor="#FFF"
        android:background="#F00"/>

</LinearLayout>
           

activity_listview_foot.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">

    <TextView
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:text="表尾"
    android:textSize="18sp"
    android:textAlignment="center"
    android:textColor="#000"
    android:background="#888"/>

</LinearLayout>
           

在 ListViewActivity.java 中添加以下代碼

//動态加載ListView表頭表尾
        final LayoutInflater inflater = LayoutInflater.from(this);
        View headView = inflater.inflate(R.layout.activity_listview_header,null,false);
        View foodView = inflater.inflate(R.layout.activity_listview_foot,null,false);

        listView.addHeaderView(headView);
        listView.addFooterView(foodView);
           

注意:這部分代碼應該添加到 setAdapter 之前。

此外,設定表頭後,表頭将成為 listView 的第一項,是以我後面點選表頭,它卻說它叫紅紅...

效果圖

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

ArrayAdapter示例

activity_list_view.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:orientation="vertical"
    tools:context=".ListViewActivity"
    android:padding="10dp">

    <ListView
        android:id="@+id/id_listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>


</LinearLayout>
           

ListViewActivity.java

package com.example.my_test;

import androidx.appcompat.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.Toast;

public class ListViewActivity extends AppCompatActivity {

    private String data[] = {"紅紅","橙橙","黃黃","綠綠","蘭蘭","紫紫","粉粉","灰灰","屎屎"};
    private ListView one_ListView;

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

        one_ListView = (ListView)findViewById(R.id.id_listview);

        //建立并設定擴充卡
        final ArrayAdapter <String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,
                data);
        one_ListView.setAdapter(adapter);

        //監聽事件
        one_ListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(ListViewActivity.this,
                        "我是"+ adapter.getItem(i),
                        Toast.LENGTH_SHORT).show();
            }
        });
    }
}
           

效果圖

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

SimpleAdapter示例

前面學習 擴充卡 的時候說到,ArrayAdapter 适用于顯示資訊比較單一的場景,若清單項中包含多種形式的資料,就不太适用了。

因而,我們這裡使用 SimpleAdapter 。

activity_listview_item.xml(子項目布局)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center|left">

    <ImageView
        android:id="@+id/id_listview_item_image"
        android:src="@drawable/user1"
        android:layout_width="100dp"
        android:layout_height="100dp"/>

    <TextView
        android:id="@+id/listview_item_name"
        android:text="紅紅"
        android:gravity="center"
        android:layout_marginLeft="50dp"
        android:textSize="50sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


</LinearLayout>
           

activity_list_view.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:orientation="vertical"
    tools:context=".ListViewActivity"
    android:padding="10dp">

    <ListView
        android:id="@+id/id_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>


</LinearLayout>
           

ListViewActivity.java

package com.example.my_test;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListViewActivity extends AppCompatActivity {

    private ListView listView;
    private SimpleAdapter simpleAdapter;

    private List<Map<String,Object>> datas = new ArrayList<Map<String,Object>>();

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

        listView = (ListView)findViewById(R.id.id_list_view);
        //添加資料
        Init_datas();
        //設定擴充卡
        simpleAdapter = new SimpleAdapter(this,
                datas,
                R.layout.activity_listview_item,
                new String[]{"img","name"},
                new int[]{R.id.id_listview_item_image,R.id.listview_item_name});
        listView.setAdapter(simpleAdapter);

    }

    private void Init_datas(){
        Map map1 = new HashMap();
        map1.put("img",R.drawable.user1);
        map1.put("name","紅紅");
        datas.add(map1);

        Map map2 = new HashMap();
        map2.put("img",R.drawable.user2);
        map2.put("name","橙橙");
        datas.add(map2);

        Map map3 = new HashMap();
        map3.put("img",R.drawable.user3);
        map3.put("name","黃黃");
        datas.add(map3);

        Map map4 = new HashMap();
        map4.put("img",R.drawable.user4);
        map4.put("name","綠綠");
        datas.add(map4);

        Map map5 = new HashMap();
        map5.put("img",R.drawable.user5);
        map5.put("name","蘭蘭");
        datas.add(map5);

        Map map6 = new HashMap();
        map6.put("img",R.drawable.user6);
        map6.put("name","紫紫");
        datas.add(map6);

        Map map7 = new HashMap();
        map7.put("img",R.drawable.user7);
        map7.put("name","粉粉");
        datas.add(map7);

        Map map8 = new HashMap();
        map8.put("img",R.drawable.user8);
        map8.put("name","灰灰");
        datas.add(map8);

        Map map9 = new HashMap();
        map9.put("img",R.drawable.user9);
        map9.put("name","屎屎");
        datas.add(map9);

    }
}
           

SimpleAdapter的構造函數如下: SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

我們執行個體化SimpleAdapter時傳入的參數分别是:
  • context:即上下文對象,這裡傳入this;
  • data:是一個包裹Map集合的List資料集,這裡傳入datas,程式初始化的資料集;
  • resource:子項布局檔案,這裡是我們自定義的activity_listview_item.xml檔案,傳入R.layout.activity_listview_item;
  • from:是一個字元串數組,字元串指的是Map中的鍵值,這裡有兩個鍵,即“img”和“name”;
  • to:是一個int型數組,表示子項布局中對應控件的id,這裡傳入ImageView的ID  R.id.id_listview_item_image

    和TextView的ID  R.id.listview_item_name 即可。

效果圖

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

BaseAdapter示例

BaseAdapter 是 SimpleAdapter 的父類,較 SimpleAdapter 來講更為靈活。之前再學習擴充卡的時候沒有使用到,這裡補上。

BaseAdapter 使用方法

1.建立一個 java 檔案 ManAdapter.java,繼承自 BaseAdapter,并且實作它的 4 個基礎方法。這四個方法分别是:
  • getCount ( ) : 傳回子項的數目,比如格子的數量
  • getItem ( ) : 根據一個索引(位置)獲得該位置的對象,傳回子項下标對應的對象
  • getItemId ( ) : 擷取條目的 id,傳回子項下标
  • getView ( ): 擷取該條目要顯示的界面,傳回子項視圖
提示:可以簡單的了解為,adapter 先從 getCount ( ) 裡确定數量,然後循環執行 getView ( ) 方法将條目一個一個繪制出來,是以必須重寫的是 getCount ( ) 和 getView ( ) 方法。而 getItem ( ) 和 getItemId ( ) 是調用某些函數才會觸發的方法。
2.ManAdapter 這個類寫好後,我們就建立一個 manAdapter。
manAdapter = new ManAdapter(ListViewActivity.this,datas);
           
3.在 ListView的 view 中,使用 setAdapter 方法傳入我們的 manAdapter 就可以用了。
listView.setAdapter(manAdapter);
           

示例

例程中使用了自定義布局,因而我還建立額一個 Man.java 作為每個子項要展示的内容

若子布局隻需要展示 TextView 這類的資料,ManAdapter.java中将datas類型修改。

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

Man.java

package com.example.my_test;

public class Man {
    private String name;
    private int imageId;

    public Man(String name,int imageId){
        this.name = name;
        this.imageId = imageId;
    }

    public String getName(){
        return name;
    }

    public int getImageId(){
        return imageId;
    }
}
           

ManAdapter.java

package com.example.my_test;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class ManAdapter extends BaseAdapter {
    private Context context;
    private List<Man> datas;

    //構造函數
    public ManAdapter(Context context,List<Man> datas){
        this.context = context;
        this.datas = datas;
    }

    //傳回子項個數
    @Override
    public int getCount(){
        return datas.size();
    }

    //傳回子項下标
    @Override
    public long getItemId(int position){
        return position;
    }

    //傳回子項下标對應的對象
    @Override
    public Object getItem(int position){
        return datas.get(position);
    }

    //傳回子項視圖
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //最慢的加載方法
        // 每次調用 getView () 的時候都去通過 findViewById 執行個體化控件
        // 因而這裡的控件必須将Image View 的android:src設定為空或者不設定(預設為空)
        // 同理,Text View 的android:text 屬性也應該同樣設定
        convertView = LayoutInflater.from(context).inflate(R.layout.activity_listview_item,null);

        ImageView img_ico = (ImageView)convertView.findViewById(R.id.id_listview_item_image);

        TextView name = (TextView)convertView.findViewById(R.id.listview_item_name);

        img_ico.setBackgroundResource(datas.get(position).getImageId());
        name.setText(datas.get(position).getName());

        return convertView;

    }

}
           

ListViewActivity.java

package com.example.my_test;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class ListViewActivity extends AppCompatActivity {

    private ListView listView;
    private ManAdapter manAdapter = null;
    private List<Man> datas = new ArrayList<Man>();

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

        initDatas();
        listView = (ListView)findViewById(R.id.id_list_view);
        manAdapter = new ManAdapter(ListViewActivity.this,datas);
        listView.setAdapter(manAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(ListViewActivity.this,
                        "我是"+ datas.get(i).getName(),
                        Toast.LENGTH_SHORT).show();
            }
        });

    }

    private void initDatas(){
        Man man1 = new Man("紅紅",R.drawable.user1);
        Man man2 = new Man("橙橙",R.drawable.user2);
        Man man3 = new Man("黃黃",R.drawable.user3);
        Man man4 = new Man("綠綠",R.drawable.user4);
        Man man5 = new Man("蘭蘭",R.drawable.user5);
        Man man6 = new Man("紫紫",R.drawable.user6);
        Man man7 = new Man("粉粉",R.drawable.user7);
        Man man8 = new Man("灰灰",R.drawable.user8);
        Man man9 = new Man("屎屎",R.drawable.user9);

        datas.add(man1);
        datas.add(man2);
        datas.add(man3);
        datas.add(man4);
        datas.add(man5);
        datas.add(man6);
        datas.add(man7);
        datas.add(man8);
        datas.add(man9);
    }
}
           

可以發現,getView( )每次都調用了findViewByld方法,而除了第一次調用給它綁定上外,我們的Item大多數情況下都是一樣的,是以我們可以改寫getView( )方法

package com.example.my_test;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class ManAdapter extends BaseAdapter {
    private Context context;
    private List<Man> datas;

    //構造函數
    public ManAdapter(Context context,List<Man> datas){
        this.context = context;
        this.datas = datas;
    }

    //傳回子項個數
    @Override
    public int getCount(){
        return datas.size();
    }

    //傳回子項下标
    @Override
    public long getItemId(int position){
        return position;
    }

    //傳回子項下标對應的對象
    @Override
    public Object getItem(int position){
        return datas.get(position);
    }

    //傳回子項視圖
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // 改進1:當 convertView 不為空的時候直接重新使用 convertView 進而減少了很多不必要的 View 的建立
        // 改進2:使用 ViewHolder 模式提高效率
        // 将 convertView 的 tag 設定為 ViewHolder, 不為空時重新使用即可 (最快的加載方式)
       Man man =(Man)getItem(position);
        View view;
        ViewHolder viewHolder;

        if(convertView == null){
            view = LayoutInflater.from(context).inflate(R.layout.activity_listview_item,null);
            viewHolder = new ViewHolder();
            viewHolder.manImage = (ImageView)view.findViewById(R.id.id_listview_item_image);
            viewHolder.manName = (TextView)view.findViewById(R.id.listview_item_name);
            view.setTag(viewHolder);
        }
        else{
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();
        }

        viewHolder.manName.setText(man.getName());
        viewHolder.manImage.setImageResource(man.getImageId());
        return view;
    }

    //建立ViewHolder類
    class ViewHolder{
        ImageView manImage;
        TextView manName;
    }

}
           

注意:

  • activity_listview_item.xml(子項目布局)與 activity_list_view.xml(主布局)均未改動。
  • 自行添加java檔案後,需要在 app -> main -> AndroidManifest.xml 中添加
  • 使用未優化的 getView () 方法時,每次都會執行個體化控件,因而這裡的控件必須将Image View 的 android:src 屬性設定為空或者不設定(預設為空),Text View 控件的 android:text 屬性也是同樣的道理。否則畫面會有疊加的效果。
【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

效果圖

【18】Android UI - ListView前言相關屬性及方法設定分割線設定表頭表尾ArrayAdapter示例SimpleAdapter示例BaseAdapter示例

可以回過頭看 設定分割線 設定表頭表尾 的例程喲~

最後推薦幾篇不錯的博文:

BaseAdapter的使用   

ListView的簡單應用   

菜鳥教程 ListView    

ListView 使用技巧