Android布局设计之ExpandableList绑定XML数据构成级联、item布局页面的控件查找及配置child事件,自定义适配显示内容

研究了N久,Google,百度了找到些靠谱的和过滤了N多不靠谱,总算实现了ExpandableList绑定XML数据构成级联、item布局页面控件查找配置事件,自定义适配内容的功能,现在就分享给各个同学。

效果:

 

 

布局:

main:

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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" >

   
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@id/title" >

        <ExpandableListView
            android:id="@id/android:list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:cacheColorHint="#ffffffff"
            android:drawSelectorOnTop="false" />

        <TextView
            android:id="@id/android:empty"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
    </LinearLayout>

</RelativeLayout>

group:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/group_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="30dp" />

    <TextView
        android:id="@+id/group_txt"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:paddingLeft="65dp"
        android:textColor="#000000"
        android:textSize="35sp" />

</RelativeLayout>

child:

<?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="wrap_content"
    android:orientation="horizontal"
    android:paddingLeft="20dp" >

    <ImageView
        android:id="@+id/child_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="30dp"
        android:paddingTop="4dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/child_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="中国"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/child_address"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="地址:xx省xx市xx" />
    </LinearLayout>

    <TextView
        android:id="@+id/child_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="地址:xx省xx市xx" />

</LinearLayout>

XML数据:

商铺类型:

<?xml version="1.0" encoding="UTF-8"?>
<shoptypes>
    <shoptype id="1">
        <name>快餐店</name>
    </shoptype>
    <shoptype id="2">
        <name>小卖部</name>
    </shoptype>
    <shoptype id="3">
        <name>网吧</name>
    </shoptype>
    <shoptype id="4">
        <name>电器店</name>
    </shoptype>
    <shoptype id="5">
        <name>银行</name>
    </shoptype>
</shoptypes>

商铺:

<?xml version="1.0" encoding="UTF-8"?>
<shops>
    <shop id="1">
        <typeid>1</typeid>
        <name>好食膳</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="2">
        <typeid>1</typeid>
        <name>好食膳</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="3">
        <typeid>1</typeid>
        <name>好食膳</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="4">
        <typeid>2</typeid>
        <name>实践部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="5">
        <typeid>2</typeid>
        <name>实践部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="6">
        <typeid>2</typeid>
        <name>实践部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="7">
        <typeid>2</typeid>
        <name>网络部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="8">
        <typeid>3</typeid>
        <name>网络部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="9">
        <typeid>3</typeid>
        <name>网络部</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="10">
        <typeid>3</typeid>
        <name>卡狄工作室</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="11">
        <typeid>4</typeid>
        <name>魔舟工作室</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="12">
        <typeid>4</typeid>
        <name>魔舟工作室</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="13">
        <typeid>4</typeid>
        <name>魔舟工作室</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="14">
        <typeid>5</typeid>
        <name>好食膳</name>
        <adress>福州市XXX</adress>
    </shop>
    <shop id="15">
        <typeid>5</typeid>
        <name>好食膳</name>
        <adress>福州市XXX</adress>
    </shop>
</shops>

java:

main:

/**
 * 
 */
package com.clshf.android.classify;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.clshf.android.R;
import com.clshf.android.domain.Shop;
import com.clshf.android.domain.ShopType;
import com.clshf.android.services.AppXmlPaseService;
import com.clshf.android.services.ExpandableListAdapterService;

import android.app.ExpandableListActivity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 作用:分类窗体 创建时间:2012-8-3 上午10:29:53 修改时间:2012年8月10日17:02:16
 * 
 * @author Hzl520
 */
public class ClassifyActivity extends ExpandableListActivity {
    
    private static final String GROUPPCITURE = "grouppciture";

    private static final String GROUPNAME = "groupname";

    private ExpandableListAdapterService exListAdapter = null;

    private static final String SUBCLASSNAMEID = "subclassid";

    private static final String SUBCLASSPICTURE = "subclasspicture";

    private static final String SUBCLASSNAME = "subclassname";

    private static final String SUBCLASSADDRESS = "subclassaddress";

 /*
     * 作用:窗体初始化.. 步骤:看注释 创建时间:2012-8-7 下午5:24:20 修改时间:2012-8-10 下午4:19:33
     * 
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.classifyview);
/** ==============配置风琴数据=============== **/ AppXmlPaseService appXmlPaseService = new AppXmlPaseService(); try { List<ShopType> shopTypes = appXmlPaseService.getPersons(this, "xml/shops/shoptype.xml"); List<Map<String, Object>> groupData = new ArrayList<Map<String, Object>>();// 父类数据 List<List<Map<String, Object>>> childData = new ArrayList<List<Map<String, Object>>>();// 子类数据 // 嵌套循环遍历数据填充至风琴列表中 for (ShopType shoptype : shopTypes) { HashMap<String, Object> curGroupMap = new HashMap<String, Object>(); groupData.add(curGroupMap); curGroupMap.put(GROUPPCITURE, R.drawable.iv_1);// 填充图片,这个随意放。 curGroupMap.put(GROUPNAME, shoptype.getName());// 填充XML中的名称 // 循环遍历子数据 List<Shop> shops = appXmlPaseService.getShops(this, "xml/shops/shop.xml"); List<Map<String, Object>> children = new ArrayList<Map<String, Object>>(); for (Shop shop : shops) { HashMap<String, Object> curChildMap = new HashMap<String, Object>(); int shoptypeid = shoptype.get_id(); if (shoptypeid != 0) { if (shoptypeid == shop.getTypeid()) { curChildMap.put(SUBCLASSPICTURE, R.drawable.iv_1); curChildMap.put(SUBCLASSNAMEID, shop.get_id() .toString()); curChildMap.put(SUBCLASSNAME, shop.getName()); curChildMap.put(SUBCLASSADDRESS, shop.getAddress()); children.add(curChildMap); } else { continue; } } } childData.add(children); } // 配置风琴列表数据 exListAdapter = new ExpandableListAdapterService( ClassifyActivity.this, groupData, R.layout.classify_group, new String[] { GROUPPCITURE, GROUPNAME }, new int[] { R.id.group_image, R.id.group_txt }, childData, R.layout.classify_child, new String[] { SUBCLASSPICTURE, SUBCLASSNAME, SUBCLASSADDRESS, SUBCLASSNAMEID }, new int[] { R.id.child_image, R.id.child_name, R.id.child_address, R.id.child_id }); // 设置风琴列表数据 setListAdapter(exListAdapter); } catch (Exception e) { e.printStackTrace(); } // 对图片ID进行处理 exListAdapter .setViewBinder(new ExpandableListAdapterService.ViewBinder() { /* * 作用:处理图片问题 步骤:看注释 创建时间:2012-8-10 下午4:19:29 修改时间:2012-8-10 * 下午4:19:29 * * @param view * * @param data * * @param textRepresentation * * @return */ @Override public boolean setViewValue(View view, Object data, String textRepresentation) { switch (view.getId()) { case R.id.group_image: { if (view instanceof ImageView) { ImageView _view = (ImageView) view; if (data instanceof Integer) { _view.setImageResource((Integer) data); } else if (data instanceof Drawable) { _view.setImageDrawable((Drawable) data); } else { throw new IllegalArgumentException( "The Data is Not a Drawable Or Resource Id!"); } } return true; } case R.id.child_image: { if (view instanceof ImageView) { ImageView _view = (ImageView) view; if (data instanceof Integer) { _view.setImageResource((Integer) data); } else if (data instanceof Drawable) { _view.setImageDrawable((Drawable) data); } else { throw new IllegalArgumentException( "The Data is Not a Drawable Or Resource Id!"); } } return true; } } return false; } }); } /* * 作用:处理子菜单点击事件 * 步骤:看注释 * 创建时间:2012-8-11 上午11:48:53 * 修改时间:2012-8-11 上午11:48:53 * @param parent * @param v * @param groupPosition * @param childPosition * @param id * @return */ @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { HashMap<String,String> map=(HashMap<String,String>)exListAdapter.getChild(groupPosition, childPosition); String sid=map.get(SUBCLASSNAMEID); Toast.makeText(this, "child--->"+sid,1).show(); return true; } }


xml数据解析:

/**
 * 
 */
package com.clshf.android.services;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import com.clshf.android.domain.Shop;
import com.clshf.android.domain.ShopType;

import android.content.Context;
import android.util.Xml;


/**
 * 作用:应用的XML数据解析处理
 * 创建时间:2012-8-10 上午10:34:30
 * 修改时间:2012-8-10 上午10:34:30
 * @author Hzl520
 */
public class AppXmlPaseService {


    /**
     * 作用:获取assets文件中的shop数据
     * 步骤:看注释
     * 创建时间:2012-8-10 下午5:31:10
     * 修改时间:2012-8-10 下午5:31:10
     * @param context
     * @param assetspath
     * @return List<Shop>
     * @throws Exception
     */
    public  List<Shop> getShops(Context context,String assetspath ) throws Exception {
        //获取xml文件流对象
        InputStream inputStream=context.getAssets().open(assetspath);
        List<Shop> shops=null;
        Shop shop=null;
        XmlPullParser parser=Xml.newPullParser();
        parser.setInput(inputStream, "UTF-8");
        //获取解析事件,和SAX类似
        int eventType=parser.getEventType();
        //使用各个事件解析XML
        while(eventType!=XmlPullParser.END_DOCUMENT){
            switch (eventType) {
            case XmlPullParser.START_DOCUMENT:
                //开始遍历节点的时候实例化集合
                shops=new ArrayList<Shop>();
                break;
            case XmlPullParser.START_TAG:
                String name=parser.getName();
                if(name.equals("shop")){
                    shop=new Shop();
                    shop.set_id(new Integer(parser.getAttributeValue(0)));
                }
                if (shop!=null) {
                    if (name.equals("typeid")) {
                        shop.setTypeid(new Integer(parser.nextText()));
                    }else if (name.equals("name")) {
                        shop.setName(parser.nextText());
                    }
                    else if (name.equals("adress")) {
                        shop.setAddress(parser.nextText());
                    }
                }
                break;
            case XmlPullParser.END_TAG:
                if(parser.getName().equals("shop")){
                    shops.add(shop);
                    shop=null;
                    }
                break;
            }
            //遍历下一个节点
            eventType=parser.next();
        }
        return shops;
    }


    /**
     * 作用:从XML中获取商店类型信息
     * 步骤:看注释
     * 创建时间:2012-7-14 上午10:31:25
     * 修改时间:2012-7-14 上午10:31:25
     * @param inputStream
     * @return
     * @throws Exception 
     */
    public  List<ShopType> getPersons(Context context,String assetspath ) throws Exception {
        //获取xml文件流对象
        InputStream inputStream=context.getAssets().open(assetspath);
        List<ShopType> shoptypes=null;
        ShopType shoptype=null;
        XmlPullParser parser=Xml.newPullParser();
        parser.setInput(inputStream, "UTF-8");
        //获取解析事件,和SAX类似
        int eventType=parser.getEventType();
        //使用各个事件解析XML
        while(eventType!=XmlPullParser.END_DOCUMENT){
            switch (eventType) {
            case XmlPullParser.START_DOCUMENT:
                //开始遍历节点的时候实例化集合
                shoptypes=new ArrayList<ShopType>();
                break;
            case XmlPullParser.START_TAG:
                String name=parser.getName();
                if(name.equals("shoptype")){
                    shoptype=new ShopType();
                    shoptype.set_id(new Integer(parser.getAttributeValue(0)));
                }
                if (shoptype!=null) {
                    if (name.equals("name")) {
                        shoptype.setName(parser.nextText());
                    }
                }
                break;
            case XmlPullParser.END_TAG:
                if(parser.getName().equals("shoptype")){
                    shoptypes.add(shoptype);
                    shoptype=null;
                    }
                break;
            }
            //遍历下一个节点
            eventType=parser.next();
        }
        return shoptypes;
    }
    
}

ExpandableList数据适配器:

package com.clshf.android.services;

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

import java.util.List;
import java.util.Map;

/**
 * 作用:自定义处理ExpandableListAdapter数据
 * 创建时间:2012-8-10 下午3:30:09
 * 修改时间:2012-8-10 下午3:30:09
 * @author Hzl520
 */
public class ExpandableListAdapterService extends BaseExpandableListAdapter {
    private ViewBinder mViewBinder;

    private List<? extends Map<String, ?>> mGroupData;
    private int mExpandedGroupLayout;
    private int mCollapsedGroupLayout;
    private String[] mGroupFrom;
    private int[] mGroupTo;

    private List<? extends List<? extends Map<String, ?>>> mChildData;
    private int mChildLayout;
    private int mLastChildLayout;
    private String[] mChildFrom;
    private int[] mChildTo;

    private LayoutInflater mInflater;

    public ExpandableListAdapterService(Context context, List<? extends Map<String, ?>> groupData,
            int groupLayout, String[] groupFrom, int[] groupTo,
            List<? extends List<? extends Map<String, ?>>> childData, int childLayout,
            String[] childFrom, int[] childTo) {
        this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, childData,
                childLayout, childLayout, childFrom, childTo);
    }

    public ExpandableListAdapterService(Context context, List<? extends Map<String, ?>> groupData,
            int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
            List<? extends List<? extends Map<String, ?>>> childData, int childLayout,
            String[] childFrom, int[] childTo) {
        this(context, groupData, expandedGroupLayout, collapsedGroupLayout, groupFrom, groupTo,
                childData, childLayout, childLayout, childFrom, childTo);
    }

    public ExpandableListAdapterService(Context context, List<? extends Map<String, ?>> groupData,
            int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
            List<? extends List<? extends Map<String, ?>>> childData, int childLayout,
            int lastChildLayout, String[] childFrom, int[] childTo) {
        mGroupData = groupData;
        mExpandedGroupLayout = expandedGroupLayout;
        mCollapsedGroupLayout = collapsedGroupLayout;
        mGroupFrom = groupFrom;
        mGroupTo = groupTo;

        mChildData = childData;
        mChildLayout = childLayout;
        mLastChildLayout = lastChildLayout;
        mChildFrom = childFrom;
        mChildTo = childTo;

        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public Object getChild(int groupPosition, int childPosition) {
        return mChildData.get(groupPosition).get(childPosition);
    }

    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    /**
     * Instantiates a new View for a child.
     * @param isLastChild Whether the child is the last child within its group.
     * @param parent The eventual parent of this new View.
     * @return A new child View
     */
    public View newChildView(boolean isLastChild, ViewGroup parent) {
        return mInflater.inflate((isLastChild) ? mLastChildLayout : mChildLayout, parent, false);
    }

    public int getChildrenCount(int groupPosition) {
        return mChildData.get(groupPosition).size();
    }

    public Object getGroup(int groupPosition) {
        return mGroupData.get(groupPosition);
    }

    public int getGroupCount() {
        return mGroupData.size();
    }

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

    /**
     * Instantiates a new View for a group.
     * @param isExpanded Whether the group is currently expanded.
     * @param parent The eventual parent of this new View.
     * @return A new group View
     */
    public View newGroupView(boolean isExpanded, ViewGroup parent) {
        return mInflater.inflate((isExpanded) ? mExpandedGroupLayout : mCollapsedGroupLayout,
                parent, false);
    }

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

    public boolean hasStableIds() {
        return true;
    }

    // --------------------------------------------------------------------------------------//

    private void bindView(View view, Map<String, ?> data, String[] from, int[] to) {
        int len = to.length;

        boolean isBound = false;
        for (int i = 0; i < len; i++) {

            final View v = view.findViewById(to[i]);

            if (v!=null) {
                final Object _data = data.get(from[i]);
                String text = _data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }
                
                if (mViewBinder != null) {//如果Binder不为空,使用Binder进行处理
                    isBound = mViewBinder.setViewValue(v, data.get(from[i]), text);
                }
                
                if (!isBound) {//如果Binder跳过,使用原来的方法进行处理
                    TextView _v = (TextView)v;
                    _v.setText((String)data.get(from[i]));
                }                
            }
        }
    }

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        View v;
        if (convertView == null) {
            v = newGroupView(isExpanded, parent);
        } else {
            v = convertView;
        }

        bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);
        return v;
    }

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
        View v;
        if (convertView == null) {
            v = newChildView(isLastChild, parent);
        } else {
            v = convertView;
        }

        bindView(v, mChildData.get(groupPosition).get(childPosition), mChildFrom, mChildTo);
        return v;
    }

    public void setViewBinder(ViewBinder mViewBinder) {
        this.mViewBinder = mViewBinder;
    }

    /**
     * 作用:提供视图渲染的绑定器 
     * 创建时间:2012-8-10 下午3:29:45
     * 修改时间:2012-8-10 下午3:29:45
     * @author Hzl520
     */
    public static interface ViewBinder {
        boolean setViewValue(View view, Object data, String textRepresentation);
    }

}

转载请注明:http://www.cnblogs.com/hzl512/archive/2012/08/11/2633664.html

原文地址:https://www.cnblogs.com/hzl512/p/2633664.html