ListView分类显示

来源:互联网 发布:淘宝如何入驻亲宝贝 编辑:程序博客网 时间:2024/05/22 06:11

第一个完整示例:

1. 引言

 

    在Android开发过程中往往有这样的需求,将ListView中的内容按年,月,日进行分类显示,要实现这样的效果我们可能有很多种方法,

 

    如:多ListView拼合,自定义ListView组件等,下面介绍一种比较简单,而且实现结构清晰的实现方式,效果图及实现如下。

 

2. 效果图

    ListView分类

3. 功能实现

 

    (1) 主布局(main.xml)实现:

view plain
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"  
  3.     android:orientation = "vertical"  
  4.     android:layout_width = "fill_parent"  
  5.     android:layout_height = "fill_parent"  
  6.     >  
  7.     <ListView  
  8.         android:id = "@+id/categoryList"  
  9.         android:layout_width = "fill_parent"   
  10.         android:layout_height = "fill_parent"  
  11.         />  
  12. </LinearLayout>   

 

    (2) 主Activity实现:

view plain
  1. package com.flora;  
  2. import android.app.Activity;  
  3. import android.os.Bundle;  
  4. import android.view.View;  
  5. import android.view.ViewGroup;  
  6. import android.widget.ArrayAdapter;  
  7. import android.widget.ListView;  
  8. import android.widget.TextView;  
  9. public class ListViewCategoryActivity extends Activity {  
  10.       
  11.     private String [] mContacts = {"马英才""张三""李四"};  
  12.     private String [] mMusic = {"素顔""庐州月""半城烟沙"};  
  13.     private String [] mEBook = {"拆掉思维里的墙""淡定力""人脉决定命脉"};  
  14.       
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);  
  19.           
  20.         mCategoryAdapter.addCategory("人名"new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mContacts));  
  21.           
  22.         mCategoryAdapter.addCategory("音乐",new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mMusic));  
  23.           
  24.         mCategoryAdapter.addCategory("书籍",new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mEBook));  
  25.           
  26.         ListView categoryList = (ListView) findViewById(R.id.categoryList);  
  27.           
  28.         categoryList.setAdapter(mCategoryAdapter);  
  29.     }  
  30.       
  31.     private CategoryAdapter mCategoryAdapter = new CategoryAdapter() {  
  32.         @Override  
  33.         protected View getTitleView(String title, int index, View convertView, ViewGroup parent) {  
  34.             TextView titleView;  
  35.               
  36.             if (convertView == null) {  
  37.                 titleView = (TextView)getLayoutInflater().inflate(R.layout.title, null);  
  38.             } else {  
  39.                 titleView = (TextView)convertView;  
  40.             }  
  41.               
  42.             titleView.setText(title);  
  43.               
  44.             return titleView;  
  45.         }  
  46.     };  
  47.       
  48. }  

 

    (3) Adapter实现:

view plain
  1. package com.flora;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4. import android.view.View;  
  5. import android.view.ViewGroup;  
  6. import android.widget.Adapter;  
  7. import android.widget.BaseAdapter;  
  8. public abstract class CategoryAdapter extends BaseAdapter {  
  9.     private List<Category> categories = new ArrayList<Category>();  
  10.       
  11.     public void addCategory(String title, Adapter adapter) {  
  12.         categories.add(new Category(title, adapter));  
  13.     }  
  14.       
  15.     @Override  
  16.     public int getCount() {  
  17.         int total = 0;  
  18.           
  19.         for (Category category : categories) {  
  20.             total += category.getAdapter().getCount() + 1;  
  21.         }  
  22.           
  23.         return total;  
  24.     }  
  25.     @Override  
  26.     public Object getItem(int position) {  
  27.         for (Category category : categories) {  
  28.             if (position == 0) {  
  29.                 return category;  
  30.             }  
  31.               
  32.             int size = category.getAdapter().getCount() + 1;  
  33.             if (position < size) {  
  34.                 return category.getAdapter().getItem(position-1);  
  35.             }  
  36.             position -= size;  
  37.         }  
  38.           
  39.         return null;  
  40.     }  
  41.     @Override  
  42.     public long getItemId(int position) {  
  43.         return position;  
  44.     }  
  45.       
  46.     public int getViewTypeCount() {  
  47.         int total = 1;  
  48.           
  49.         for (Category category : categories) {  
  50.             total += category.getAdapter().getViewTypeCount();  
  51.         }  
  52.           
  53.         return total;  
  54.     }  
  55.     public int getItemViewType(int position) {  
  56.         int typeOffset = 1;  
  57.           
  58.         for (Category category : categories) {  
  59.             if (position == 0) {  
  60.                 return 0;  
  61.             }  
  62.               
  63.             int size = category.getAdapter().getCount() + 1;  
  64.             if (position < size) {  
  65.                 return typeOffset + category.getAdapter().getItemViewType(position - 1);  
  66.             }  
  67.             position -= size;  
  68.               
  69.             typeOffset += category.getAdapter().getViewTypeCount();  
  70.         }  
  71.           
  72.         return -1;  
  73.     }  
  74.     @Override  
  75.     public View getView(int position, View convertView, ViewGroup parent) {  
  76.         int categoryIndex = 0;  
  77.           
  78.         for (Category category : categories) {  
  79.             if (position == 0) {  
  80.                 return getTitleView(category.getTitle(), categoryIndex,convertView, parent);  
  81.             }  
  82.             int size = category.getAdapter().getCount()+1;  
  83.             if (position < size) {  
  84.                 return category.getAdapter().getView(position - 1, convertView, parent);  
  85.             }  
  86.             position -= size;  
  87.               
  88.             categoryIndex++;  
  89.         }  
  90.           
  91.         return null;  
  92.     }  
  93.       
  94.     protected abstract View getTitleView(String caption,int index,View convertView,ViewGroup parent);  
  95.       
  96. }   

 

    (4) 分类ValueBean实现:

view plain
  1. package com.flora;  
  2. import android.widget.Adapter;  
  3. public class Category {  
  4.     private String mTitle;  
  5.       
  6.     private Adapter mAdapter;  
  7.     public Category(String title, Adapter adapter) {  
  8.         mTitle = title;  
  9.         mAdapter = adapter;  
  10.     }  
  11.       
  12.     public void setTile(String title) {  
  13.         mTitle = title;  
  14.     }  
  15.       
  16.     public String getTitle() {  
  17.         return mTitle;  
  18.     }  
  19.       
  20.     public void setAdapter(Adapter adapter) {  
  21.         mAdapter = adapter;  
  22.     }  
  23.       
  24.     public Adapter getAdapter() {  
  25.         return mAdapter;  
  26.     }  
  27.       
  28. }   

 

    (5) 分类Title实现:

view plain
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <TextView  
  3.     xmlns:android = "http://schemas.android.com/apk/res/android"  
  4.     android:layout_width = "match_parent"  
  5.     android:layout_height = "match_parent"  
  6.     android:minHeight = "30dip"  
  7.     android:gravity = "center_vertical"  
  8.     android:paddingLeft = "10dip"  
  9.     android:background = "@color/title_background_color"  
  10.     />   


第二个完整示例

今天和大家分享关于“listview的分类显示”。现在有比较多的应用都有这个效果,比如在androidICS风格的“设置”选项里面就有这个效果,先看看效果:

ListView分类显示

实现这个效果比较简单,在填充listviewadapter的时候,我们都会通过继承BaseAdapter来写我们自己的adapterlistview里面的item是通过getView(int position, View convertView, ViewGroup parent) 实现。其实这边有实现预加载,你只要在getview方法里面打印出log信息就会发现,listview刚开始显示的时候getview不会返回所有的item,只是返回了前面几个,当你往下拖拽的时候getview方法会加载剩下的item。这样做的好处大家都知道,如果不这样做估计早就出现了内存泄漏了。

好吧,我们回到主题,实现分类显示只需要你把你显示的数据打包好。Listview里面的item都是通过getView来生成,所以可以这样,如果在getview里面生成item的时候,你返回两次convertView不就可以了吗?也就是说平时我们都是通过convertView来返回item,但是现在多了一个操作就是你根据自身打包的数据,如果当前返回的item是和之前显示的item不属于同一类就返回两次convertView。这样理解这个就好实现多了吧。注意的是像上面图上“Label”、“类别1”、“类别2”是不可点击的,只要实现BaseAdapter里面的isEnabled(int position)的方法就可以。

下面介绍的实现方式是运用了工厂模式实现,下面是草图

ListView分类显示

新建了一个ListItems接口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/***
 * <span class="referer">@author</span>  huangsm
 * @date 2012-8-29
 * <span class="referer">@email</span>  huangsanm@gmail.com<script cf-hash="f9e31" type="text/javascript">
/* <![CDATA[ */!function(){try{var t="currentScript"in document?document.currentScript:function(){for(var t=document.getElementsByTagName("script"),e=t.length;e--;)if(t[e].getAttribute("cf-hash"))returnt[e]}();if(t&&t.previousSibling){var e,r,n,i,c=t.previousSibling,a=c.getAttribute("data-cfemail");if(a){for(e="",r=parseInt(a.substr(0,2),16),n=2;a.length-n;n+=2)i=parseInt(a.substr(n,2),16)^r,e+=String.fromCharCode(i);e=document.createTextNode(e),c.parentNode.replaceChild(e,c)}}}catch(u){}}();/* ]]> */</script>
 @desc接口
 */
publicinterface ListItems {
 
    publicint getLayout();
     
    publicboolean isClickable();
     
    publicView getView(Context context, View convertView, LayoutInflater inflater);
     
}

其中LabelItem和ContentItem分别是显示的“类别”和“内容”,他们分别实现ListItems接口。LabelItem实现: 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/***
 * <span class="referer">@author</span>  huangsm
 * @date 2012-8-29
 * <span class="referer">@email</span>  huangsanm@gmail.com<script cf-hash="f9e31" type="text/javascript">
/* <![CDATA[ */!function(){try{var t="currentScript"in document?document.currentScript:function(){for(var t=document.getElementsByTagName("script"),e=t.length;e--;)if(t[e].getAttribute("cf-hash"))returnt[e]}();if(t&&t.previousSibling){var e,r,n,i,c=t.previousSibling,a=c.getAttribute("data-cfemail");if(a){for(e="",r=parseInt(a.substr(0,2),16),n=2;a.length-n;n+=2)i=parseInt(a.substr(n,2),16)^r,e+=String.fromCharCode(i);e=document.createTextNode(e),c.parentNode.replaceChild(e,c)}}}catch(u){}}();/* ]]> */</script>
 @desc标签
 */
publicclass LabelItem implementsListItems {
 
    privateString mLabel;
    publicLabelItem(String label){
        mLabel = label;
    }
     
    @Override
    publicint getLayout() {
        returnR.layout.label_layout;
    }
 
    @Override
    publicboolean isClickable() {
        returnfalse;
    }
 
    @Override
    publicView getView(Context context, View convertView, LayoutInflater inflater) {
        convertView = inflater.inflate(getLayout(), null);
        TextView title = (TextView) convertView;
        title.setText(mLabel);
        returnconvertView;
    }
 
}

ContentItem的实现: 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/***
 * <span class="referer">@author</span>  huangsm
 * @date 2012-8-29
 * <span class="referer">@email</span>  huangsanm@gmail.com<script cf-hash="f9e31" type="text/javascript">
/* <![CDATA[ */!function(){try{var t="currentScript"in document?document.currentScript:function(){for(var t=document.getElementsByTagName("script"),e=t.length;e--;)if(t[e].getAttribute("cf-hash"))returnt[e]}();if(t&&t.previousSibling){var e,r,n,i,c=t.previousSibling,a=c.getAttribute("data-cfemail");if(a){for(e="",r=parseInt(a.substr(0,2),16),n=2;a.length-n;n+=2)i=parseInt(a.substr(n,2),16)^r,e+=String.fromCharCode(i);e=document.createTextNode(e),c.parentNode.replaceChild(e,c)}}}catch(u){}}();/* ]]> */</script>
 @desc内容
 */
publicclass ContentItem implementsListItems {
 
    privateItem mItem;
    publicContentItem(Item item){
        mItem = item;
    }
     
    @Override
    publicint getLayout() {
        returnR.layout.content_layout;
    }
 
    @Override
    publicboolean isClickable() {
        returntrue;
    }
 
    @Override
    publicView getView(Context context, View convertView, LayoutInflater inflater) {
        convertView = inflater.inflate(getLayout(), null);
        ImageView iv = (ImageView) convertView.findViewById(R.id.content_image);
        iv.setImageResource(mItem.getResid());
        TextView tv = (TextView) convertView.findViewById(R.id.content_text);
        tv.setText(mItem.getTitle());
        returnconvertView;
    }
}

在activity中实现就相对来说比较麻烦一些。定义一个以ListItems为泛型的list集合mListItems,作为填充adapter的数据源,然后在adapter里面处理就很简单:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
classPartAdapter extendsBaseAdapter {
 
        @Override
        publicint getCount() {
            returnmListItems.size();
        }
 
        @Override
        publicObject getItem(intposition) {
            returnmListItems.get(position);
        }
 
        @Override
        publiclong getItemId(intposition) {
            returnposition;
        }
         
        @Override
        publicboolean isEnabled(intposition) {
            returnmListItems.get(position).isClickable();
        }
 
        @Override
        publicView getView(intposition, View convertView, ViewGroup parent) {
            returnmListItems.get(position).getView(mContext, convertView, mInflater);
        }
    }

接下来是初始化数据,需要注意的是LabelItem的初始化,不过这个动作可以在你打包数据的时候处理好,这样在activity里面就不会那么麻烦了 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
    protectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.part_listview);
        mListView = (ListView) findViewById(R.id.part_list);
        mContext = this;
        mInflater = LayoutInflater.from(mContext);
        mListItems =  newArrayList
   <listitems>     ();
         
        //初始化数据
        LabelItem label1 = newLabelItem("Label");
        mListItems.add(label1);
         
        Item item1 = newItem();
        item1.setResid(R.drawable.ic_launcher);
        item1.setTitle(getString(R.string.app_name));
        ContentItem content1 = newContentItem(item1);
        mListItems.add(content1);
         
        for(inti = 0; i < 3; i++) {
            LabelItem label = newLabelItem("类别"+ (i + 1));
            mListItems.add(label);
             
            for(intj = 0; j < 3; j++) {
                Item item = newItem();
                item.setResid(R.drawable.ic_launcher_biz);
                item.setTitle("Content"+ (i + 1));
                ContentItem content = newContentItem(item);
                mListItems.add(content);
            }
        }
         
        //设置adapter
        PartAdapter adapter = newPartAdapter();
        mListView.setAdapter(adapter);
    }
   </listitems>

第三个完整示例:

我们有时候会遇到这么一个情况。就是我在一个ListView里面需要显示的东西其实是有种类之分的。比如我要分冬天,夏天,秋天,春天,然后在这每个季节下面再去加载各自的条目数据。还有,比如我们的通讯录,我们需要按A,B,C这样的字母顺序分类然后显示。这个怎么实现呢?

下面我们不用ExpandableListView,而是只用ListView来实现这一显示效果。

MainActivity.java

package com.xzq.listviewadapter;import android.app.Activity;import android.os.Bundle;import android.view.Window;import android.widget.ListView;public class MainActivity extends Activity {private String[] string = { "A", "B", "C", "D", "E", "F", "G", "H", "I","J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V","W", "X", "Y", "Z" };/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.main);ListView listview = (ListView) findViewById(R.id.listview);MyCustomAdapter adapter = new MyCustomAdapter(this);int size = string.length;for (int i = 0; i < size; i++) {adapter.addSeparatorItem(string[i]);for (int k = 0; k < 5; k++) {adapter.addItem("item " + k);}}listview.setAdapter(adapter);}}

MyCustomAdapter.java

package com.xzq.listviewadapter;import java.util.ArrayList;import java.util.TreeSet;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class MyCustomAdapter extends BaseAdapter {private static final int TYPE_ITEM = 0;private static final int TYPE_SEPARATOR = 1;private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;private ArrayList<String> data = new ArrayList<String>();private LayoutInflater inflater;private TreeSet<Integer> set = new TreeSet<Integer>();public MyCustomAdapter(Context context) {inflater = LayoutInflater.from(context);}public void addItem(String item) {data.add(item);}public void addSeparatorItem(String item) {data.add(item);set.add(data.size() - 1);}public int getItemViewType(int position) {return set.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;}@Overridepublic int getViewTypeCount() {return TYPE_MAX_COUNT;}@Overridepublic int getCount() {return data.size();}@Overridepublic Object getItem(int position) {return data.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;int type = getItemViewType(position);if (convertView == null) {holder = new ViewHolder();switch (type) {case TYPE_ITEM:convertView = inflater.inflate(R.layout.item1, null);holder.textView = (TextView) convertView.findViewById(R.id.item1);break;case TYPE_SEPARATOR:convertView = inflater.inflate(R.layout.item2, null);holder.textView = (TextView) convertView.findViewById(R.id.item2);break;}convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.textView.setText(data.get(position));return convertView;}public static class ViewHolder {public TextView textView;}}

main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#ffffff"android:orientation="vertical" ><ListViewandroid:id="@+id/listview"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/hello" /></LinearLayout>

item1.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#ffffff"android:orientation="vertical" ><TextViewandroid:id="@+id/item1"android:layout_width="fill_parent"android:layout_height="30dip"android:gravity="center_vertical" /></LinearLayout>

item2.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/item2"android:layout_width="fill_parent"android:layout_height="30dip"android:background="#3c4857"android:gravity="center_vertical" /></LinearLayout>
0 0
原创粉丝点击