Android學習(五)分組ListView(Sectioned Headers)


問題

當你想展示一個分類的數據列表比如依據時間、日期、產品累不或者銷售價格序等
解決方案
我們可以使用“Sectioned headers“(這里不知道應該具體叫啥,故未翻譯,可以理解為分割頭,或者分組) ListView.這里我們自定義一個Adapter,使用不同類型的視圖和其對應的Adapter來實現,這里我們必須關注2個方法:

int getItemViewType( int position)
為特定的視圖返回getView( int, View, ViewGroup)即將構建的視圖類型
int getViewTypeCount()
返回getView( int, View, ViewGroup)即將構建的視圖的視圖類型個數.

下面是我們的實現代碼:

我們這里構建我們的Android工程,並添加一個GroupListVeiwActivity(Project的包名:com.jeriffe.app)

首先我們需要定義我們的Layout文件:

注:這里我們有3個Layout文件,分別是activity的Layout,sectionsHeader的Layout,及listView Item的Layout,以下只是演示,故Layout代碼文件格式並未應用Theme及Style

activity_group_list_veiw.xml(activity的Layout)

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

    <ListView
        android:id="@+id/add_journalentry_menuitem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:id="@+id/list_journal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

group_list_header.xml(sectionsHeader的Layout)

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_header_title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@color/gray"
    android:paddingBottom="2dip"
    android:paddingLeft="5dip"
    android:paddingTop="2dip"
    android:textColor="@color/black" />

(listView Item的Layout)

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_item_title"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:paddingBottom="10dip"
    android:paddingLeft="15dip"
    android:paddingTop="10dip" />

接下來便是我們需要自定義的一個Adapter

我們添加一個新的類:SeparatedListAdapter 繼承自BaseAdapter適配器類,以下代碼已經很直白,關鍵代碼已經添加了注釋,最重要的4個方法如下粗體所示

package com.jeriffe.app;

import java.util.LinkedHashMap;
import java.util.Map;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;

public class SeparatedListAdapter extends BaseAdapter {
    public final Map<String, Adapter> sections = new LinkedHashMap<String, Adapter>();
    public final ArrayAdapter<String> headers;
    public final static int TYPE_SECTION_HEADER = 0;

    public SeparatedListAdapter(Context context) {
        headers = new ArrayAdapter<String>(context, R.layout.group_list_header);
    }

    public void addSection(String section, Adapter adapter) {
        this.headers.add(section);
        this.sections.put(section, adapter);
    }

    public Object getItem(int position) {
        for (Object section : this.sections.keySet()) {
            Adapter adapter = sections.get(section);
            int size = adapter.getCount() + 1;
            // check if position inside this section
            if (position == 0)
                return section;
            if (position < size)
                return adapter.getItem(position - 1);
            // otherwise jump into next section
            position -= size;
        }
        return null;
    }

    public int getCount() {
        // total together all sections, plus one for each section header
        int total = 0;
        for (Adapter adapter : this.sections.values())
            total += adapter.getCount() + 1;
        return total;
    }

    public boolean areAllItemsSelectable() {
        return false;
    }

    @Override
    public int getViewTypeCount() {
        // assume that headers count as one, then total all sections
        int total = 1;
        for (Adapter adapter : this.sections.values())
            total += adapter.getViewTypeCount();
        return total;
    }

    @Override
    public int getItemViewType(int position) {
        int type = 1;
        for (Object section : this.sections.keySet()) {
            Adapter adapter = sections.get(section);
            int size = adapter.getCount() + 1;
            // check if position inside this section
            if (position == 0)
                return TYPE_SECTION_HEADER;
            if (position < size)
                return type + adapter.getItemViewType(position - 1);

            // otherwise jump into next section
            position -= size;
            type += adapter.getViewTypeCount();
        }
        return -1;
    }

    @Override
    public boolean isEnabled(int position) {
        // 設置header enabled is false,通俗點就是點擊header無效
        return (getItemViewType(position) != TYPE_SECTION_HEADER);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        int sectionnum = 0;
        for (Object section : this.sections.keySet()) {
            Adapter adapter = sections.get(section);
            int size = adapter.getCount() + 1;

            // check if position inside this section
            if (position == 0)
                return headers.getView(sectionnum, convertView, parent);
            if (position < size)
                return adapter.getView(position - 1, convertView, parent);

            // otherwise jump into next section
            position -= size;
            sectionnum++;
        }
        return null;
    }

    public long getItemId(int position) {
        return position;
    }
}

接下來便是我們的Activity類

GroupListVeiwActivity類比較簡單就是構建UI,並初始化Adapter來展示數據:

package com.jeriffe.app;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class GroupListVeiwActivity extends Activity {
    // SectionHeaders
    private final static String[] days = new String[]{"2012-04-06",
            "2012-05-08", "2012-09-28", "2012-10-16", "2012-12-03"};

    // Section Contents
    private final static String[][] notes = new String[][]{
            {"陰轉多雲", "12℃/25℃", "穿衣指數:天氣較熱,建議着短裙、短褲、短套裝。"},
            {"晴天", "22℃/34℃", "穿衣指數:天氣大熱,建議着短裙、短褲、注意預防中暑。"},
            {"小雨", "8℃/16℃", "穿衣指數:天氣微冷,建議着秋季服裝。"},
            {"中雨", "5℃/12℃", "穿衣指數:天氣較冷,建議着秋季服裝。"},
            {"小雪", "-1℃/6℃", "穿衣指數:天氣寒冷,建議冬季服裝。"}};

    // ListView Contents
    private ListView journalListView;
    // Adapter for ListView Contents
    private SeparatedListAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_group_list_veiw);

        setupViews();
    }

    private void setupViews() {

        // Create and Initialize the ListView Adapter
        initializeAdapter();

        // Get a reference to the ListView holder
        journalListView = (ListView) this.findViewById(R.id.list_journal);
        journalListView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long duration) {
                String item = (String) adapter.getItem(position);
                Toast.makeText(getApplicationContext(), item,
                        Toast.LENGTH_SHORT).show();
            }
        });
        // Set the adapter on the ListView holder
        journalListView.setAdapter(adapter);
    }

    private void initializeAdapter() {
        adapter = new SeparatedListAdapter(this);

        for (int index = 0; index < days.length; index++) {
            ArrayAdapter<String> listadapter = new ArrayAdapter<String>(this,
                    R.layout.group_list_item, notes[index]);
            adapter.addSection(days[index], listadapter);
        }
    }
}

好了到此已經相關代碼已經Over,粘貼代碼到自己構建Project,編譯即可運行(當然String.xml及Color.xml還是要自己來添加的),下面來一張運行效果圖:

注:這里,本人運行環境是Android4.1.2

image_thumb3

以下文章探討了其他的實現方式:

1.用2個Adapter數據源:一個是Header數據源,一個是包含Item的數據源,界面數據全部來自Item數據源

,自定義Adapter繼承自ArrayAdapter<String>,其主要核心代碼是getView方法,詳細可見博客原文。

原文地址:http://www.cnblogs.com/qianxudetianxia/archive/2011/06/07/2074326.html

注:下面的代碼,group_list_item_text再給TextVeiw設置文本的時候要留意:Header及Item的ID是一致的,詳細可以見原文,

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    //根據標簽類型加載不通的布局模板
    if(listTag.contains(getItem(position))){
        //如果是標簽項
        view = LayoutInflater.from(getContext()).inflate(R.layout.group_list_item_tag, null);
    }else{              
        //否則就是數據項了      
        view = LayoutInflater.from(getContext()).inflate(R.layout.group_list_item, null);
    }
    //顯示名稱
    TextView textView = (TextView) view.findViewById(R.id.group_list_item_text);
    textView.setText(getItem(position));
    //返回重寫的view
    return view;
}

2.使用第三方插件,詳細我也為研究,感興趣的同志見:http://code.google.com/p/android-section-list/

3.利用GONE Visibility,具體的實現可見這里:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=157934&extra=page%3D1&page=1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM