一步一步学android控件(之二十一)—— ListView & ExpandableListView

关于ListView的使用可参见一步一步学android控件(之一) —— 开始篇 ,本文主要讲ExpandableListView。

ExpandableListView是一个二级列表,每一个组(Group)可以独立的展开子项目。今天做的效果:同一时刻只有一个Group展开子项目;默认没有子项目展开;点击内容时,显示一个Toast(当前点击的Item的名字)。先看效果图:


老规矩,先看布局文件:

1、界面布局文件widget_expandable_list_view.xml , 使用一个ExpandableListView:

<?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="match_parent"
    android:orientation="vertical" >

    <ExpandableListView
        android:id="@+id/show_expandable_list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         ><!-- android:drawSelectorOnTop="false" -->
    </ExpandableListView>

</LinearLayout>

2、每一个组项的布局文件:expandable_list__group_item_view.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/expandable_list_group_text"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/widget_button_drawable"
    android:paddingLeft="36dp"
    android:paddingTop="20dp"
    android:paddingBottom="20dp"
    android:gravity="center_vertical"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:textColor="@color/auto_complete_font_color" />
3、组中每一个item中的布局文件expandable_child_view_item.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="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/special_name_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@color/auto_complete_font_color"
        android:background="@drawable/widget_button_pure_color"
        android:paddingTop="10dp"
        android:paddingBottom="10dp" />

</LinearLayout>

4、activity——WidgetExpandableListViewActivity.java(该文所有的代码都在这里面了)

package com.xy.zt.selfdefinewieget;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;

public class WidgetExpandableListViewActivity extends Activity implements
        ExpandableListView.OnGroupExpandListener, ExpandableListView.OnChildClickListener {

    private static HashMap<String, ArrayList<String>> mCollegeInfo = new HashMap<String, ArrayList<String>>();
    private static String academies[] = {
            "信息科学与技术学院", "商学院", "信息管理学院", "外国语学院", "核自院", "广播影视学院", "能源学院", "政治学院", "文法学院"
    };
    static {

        String specialty[][] = {
                {
                        "物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学", "软件工程",
                        "通信工程", "物联网工程", "数字媒体技术", "电子信息工程", "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程",
                        "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
                        "工业设计", "工业工程"
                },
                {
                        "会计系", "工商管理系", "经贸系"
                },
                {
                        "物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学"
                },
                {
                        "国际经济与贸易", "市场营销", "会计学", "经济学", "财务管理"
                },
                {
                        "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程", "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
                        "工业设计", "工业工程"
                }, {
                        "播音与主持艺术", "舞蹈编导", "音乐表演", "动画", "摄影"
                }, {
                        "石油工程"
                }, {
                        "哲学", "法学", "管理学", "教育学"
                }, {
                        "社会学", "公共事业管理"
                }
        };
        String key;
        ArrayList<String> value;
        for (int i = 0; i < academies.length; i++) {
            key = academies[i];
            value = new ArrayList<String>();
            for (int j = 0; j < specialty[i].length; j++) {
                value.add(specialty[i][j]);
            }
            mCollegeInfo.put(key, value);
        }
    }
    private ExpandableListView mExList;
    private ExpandableAdapterDemo mExAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.widget_expandable_list_view);
        init();

    }

    private void init() {
        mExAdapter = new ExpandableAdapterDemo(this, mCollegeInfo, academies);
        mExList = (ExpandableListView) findViewById(R.id.show_expandable_list_view);
        mExList.setAdapter(mExAdapter);
        mExList.setOnGroupExpandListener(this);
        mExList.setOnChildClickListener(this);
    }

    private static class ExpandableAdapterDemo extends BaseExpandableListAdapter {

        LayoutInflater mInflater;
        private HashMap<String, ArrayList<String>> mData; // group content
        private String[] mAcademy;
        private Context mContext;

        public ExpandableAdapterDemo(Context context, HashMap<String, ArrayList<String>> data,
                String[] academy) {
            if (context == null || data == null || academy == null)
                throw new IllegalArgumentException(
                        "please check arguments in construct method ExpandableAdapterDemo !...");
            mContext = context;
            mInflater = LayoutInflater.from(mContext);
            mData = data;
            mAcademy = academy;
        }

        // private boolean isDataEmpty() {
        // return mData == null || mAcademy == null || mAcademy.length == 0 ||
        // mData.isEmpty();
        // }

        public Object getChild(int groupPos, int childPos) {
            return mData.get(mAcademy[groupPos]).get(childPos);
        }

        public long getChildId(int groupPos, int childPos) {
            return childPos;
        }

        public View getChildView(int groupPos, int childPos,
                boolean isLastChild, View convertView, ViewGroup parent) {
            ChildHolder holder;
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.expandable_child_view_item, null);
                holder = new ChildHolder();
                convertView.setTag(holder);
            } else {
                holder = (ChildHolder) convertView.getTag();
            }
            holder.mSpecial = (TextView) convertView.findViewById(R.id.special_name_text);
            holder.mSpecial.setText(mData.get(mAcademy[groupPos]).get(childPos));
            return convertView;
        }

        public int getChildrenCount(int groupPos) {
            return mData.get(mAcademy[groupPos]).size();
        }

        public Object getGroup(int groupPosition) {
            return mAcademy[groupPosition];
        }

        public int getGroupCount() {
            return mAcademy.length;
        }

        public long getGroupId(int groupPosition) {
            return groupPosition;
        }

        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
                ViewGroup parent) {
            GroupHolder holder;
            if (convertView == null) {
                holder = new GroupHolder();
                convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
                convertView.setTag(holder);
            } else {
                holder = (GroupHolder) convertView.getTag();
            }
            holder.mAcademyName = (TextView) convertView
                    .findViewById(R.id.expandable_list_group_text);
            holder.mAcademyName.setText(mAcademy[groupPosition]);
            return convertView;
        }

        public boolean hasStableIds() {
            return true;
        }

        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }
    }

    private static class GroupHolder {
        public TextView mAcademyName;
    }

    private static class ChildHolder {
        public TextView mSpecial;
    }

    public void onGroupExpand(int groupPos) {
        int groupCount = mExList.getCount();
        for (int i = 0; i < groupCount; i++) {
            if (i != groupPos) {
                mExList.collapseGroup(i);
            }
        }
    }

    public boolean onChildClick(ExpandableListView exList, View v, int groupPos, int childPos,
            long id) {
        TextView tv = (TextView) v.findViewById(R.id.special_name_text);
        Toast.makeText(this, "您所选择的的专业: " + tv.getText(), Toast.LENGTH_LONG).show();
        return true;
    }

}

代码中首先准备好要显示的数据:

private static HashMap<String, ArrayList<String>> mCollegeInfo = new HashMap<String, ArrayList<String>>();
    private static String academies[] = {
            "信息科学与技术学院", "商学院", "信息管理学院", "外国语学院", "核自院", "广播影视学院", "能源学院", "政治学院", "文法学院"
    };
    static {

        String specialty[][] = {
                {
                        "物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学", "软件工程",
                        "通信工程", "物联网工程", "数字媒体技术", "电子信息工程", "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程",
                        "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
                        "工业设计", "工业工程"
                },
                {
                        "会计系", "工商管理系", "经贸系"
                },
                {
                        "物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学"
                },
                {
                        "国际经济与贸易", "市场营销", "会计学", "经济学", "财务管理"
                },
                {
                        "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程", "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
                        "工业设计", "工业工程"
                }, {
                        "播音与主持艺术", "舞蹈编导", "音乐表演", "动画", "摄影"
                }, {
                        "石油工程"
                }, {
                        "哲学", "法学", "管理学", "教育学"
                }, {
                        "社会学", "公共事业管理"
                }
        };
        String key;
        ArrayList<String> value;
        for (int i = 0; i < academies.length; i++) {
            key = academies[i];
            value = new ArrayList<String>();
            for (int j = 0; j < specialty[i].length; j++) {
                value.add(specialty[i][j]);
            }
            mCollegeInfo.put(key, value);
        }
    }
最终的数据最后存到一个HashMap中。接下来就是初始化控件信息:

private void init() {
        mExAdapter = new ExpandableAdapterDemo(this, mCollegeInfo, academies);
        mExList = (ExpandableListView) findViewById(R.id.show_expandable_list_view);
        mExList.setAdapter(mExAdapter);
        mExList.setOnGroupExpandListener(this);
        mExList.setOnChildClickListener(this);
    }

上述代码中使用到了mExAdapter,其详细实现如下:

private static class ExpandableAdapterDemo extends BaseExpandableListAdapter {

        LayoutInflater mInflater;
        private HashMap<String, ArrayList<String>> mData; // group content
        private String[] mAcademy;
        private Context mContext;

        public ExpandableAdapterDemo(Context context, HashMap<String, ArrayList<String>> data,
                String[] academy) {
            if (context == null || data == null || academy == null)
                throw new IllegalArgumentException(
                        "please check arguments in construct method ExpandableAdapterDemo !...");
            mContext = context;
            mInflater = LayoutInflater.from(mContext);
            mData = data;
            mAcademy = academy;
        }

        public Object getChild(int groupPos, int childPos) {
            return mData.get(mAcademy[groupPos]).get(childPos);
        }

        public long getChildId(int groupPos, int childPos) {
            return childPos;
        }

        public View getChildView(int groupPos, int childPos,
                boolean isLastChild, View convertView, ViewGroup parent) {
            ChildHolder holder;
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.expandable_child_view_item, null);
                holder = new ChildHolder();
                convertView.setTag(holder);
            } else {
                holder = (ChildHolder) convertView.getTag();
            }
            holder.mSpecial = (TextView) convertView.findViewById(R.id.special_name_text);
            holder.mSpecial.setText(mData.get(mAcademy[groupPos]).get(childPos));
            return convertView;
        }

        public int getChildrenCount(int groupPos) {
            return mData.get(mAcademy[groupPos]).size();
        }

        public Object getGroup(int groupPosition) {
            return mAcademy[groupPosition];
        }

        public int getGroupCount() {
            return mAcademy.length;
        }

        public long getGroupId(int groupPosition) {
            return groupPosition;
        }

        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
                ViewGroup parent) {
            GroupHolder holder;
            if (convertView == null) {
                holder = new GroupHolder();
                convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
                convertView.setTag(holder);
            } else {
                holder = (GroupHolder) convertView.getTag();
            }
            holder.mAcademyName = (TextView) convertView
                    .findViewById(R.id.expandable_list_group_text);
            holder.mAcademyName.setText(mAcademy[groupPosition]);
            return convertView;
        }

        public boolean hasStableIds() {
            return true;
        }

        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }
    }
插句题外话:写的过程中冒出一个想法,如果将每个组中Item再使用一个ListView如何? ~_~ . 有空可以试试。

整个内容就跟写ListView 的Adapter差不多了。


下述代码实现了每次点击的时候只有一个组(Group)被展开:

public void onGroupExpand(int groupPos) {
        int groupCount = mExList.getCount();
        for (int i = 0; i < groupCount; i++) {
            if (i != groupPos) {
                mExList.collapseGroup(i);
            }
        }
    }
注意:开发中有时候在点击了Group项后才从网络上加载要显示的数据,这时将代码写到 ExpandableListView.OnGroupClickListener 中或许更好 。


对group中item的点击事件的响应ExpandableListView.OnChildClickListener,代码中点击item时显示Toast,并告知系统响应事件已经处理。

public boolean onChildClick(ExpandableListView exList, View v, int groupPos, int childPos,
            long id) {
        TextView tv = (TextView) v.findViewById(R.id.special_name_text);
        Toast.makeText(this, "您所选择的的专业: " + tv.getText(), Toast.LENGTH_LONG).show();
        return true;
    }

5、在ViewData.java中添加如下内容(此部分内容可选):

public static final int EXPANDABLE_LIST_VIEW_ID = WIDGET_SCROLL_ID + 1;
    public static final String EXPANDABLE_LIST_VIEW_NAME = "ExpandableListView";
private static final ViewData mExpandableListView = new ViewData(EXPANDABLE_LIST_VIEW_NAME,
            EXPANDABLE_LIST_VIEW_ID);
 View_Datas.add(mExpandableListView);
WidgetsAdapter的handleItemClicked中添加如下内容:

case ViewData.EXPANDABLE_LIST_VIEW_ID:
            intent.setClass(mContext, WidgetExpandableListViewActivity.class);
            mContext.startActivity(intent);
            break;

6、在此记录下与本文无关的内容—— ListView的优化

关于ListView的优化呢,网络上也有很多内容介绍了,其目的呢就是提高ListView的效率。这里就记录下一种常用的优化方案:

1、使用一个static的类存储每个item中的View。如上述代码中

private static class GroupHolder {
        public TextView mAcademyName;
    }
2、getView中代码的写法
GroupHolder holder;
            if (convertView == null) {
                holder = new GroupHolder();
                convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
                convertView.setTag(holder);
            } else {
                holder = (GroupHolder) convertView.getTag();
            }
... ...
... ...
return convertView;

ExpandableListView优化同理:在Adapter的getGroupView和getChildView中分别向上述步骤添加代码即可。


ListView和ExpandableListView就完了,下一个控件 GridView 。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值