这篇随身笔带来的是结合聚合数据“菜谱大全”做的一个菜谱可折叠一级+二级列表。

先发来一些截图一睹为快吧。

ExpandableListView 可用于折叠型菜单列表,其布局主要通过getGroupView和getChildView两种的重写来实现。在子列表项目比较多的情况下,可以通过GridView来布局子列表。

下面来说说ExpandableListView的适配器ExpandableListadapter的一些变量和方法:

一、首先:我们知道ExpandableListView分为父列表和子列表,其中 父列表通过一维数组String[]进行数据填充,子类表通过二维数组String[][]填充。

ExpandableListadapter重要的方法:

public long getGroupId(int groupPosition) 根据groupPosition获取与该组相关联的标识

    public Object getGroup(int groupPosition) 获取与在给定组相关的数据。

public int getGroupCount() 返回Group的组数目。

    getChildId (int groupPosition, int childPosition) 获取与在给定组给予孩子相关的数据。

    getChildrenCount (int groupPosition) 返回在指定Group的Child数目。

public long getChildId(int groupPosition, int childPosition)  获取与在给定组给予孩子相关联的标识。

public View getGroupView(int groupPosition, boolean isExpanded, View convertView,

ViewGroup parent)  对父列表视图进行布局。

public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
           ViewGroup parent)  对应于指定位置的子视图布局。

girdview用来进行网格布局,个人认为,主要girdview用于项目数较多的场景,多用于图片加文字的布局方式。,其布局优点:呈现的信息量大,一目了然。这里采用比较简单适配器SimpleAdapter。

SimpleAdapter(context, data, resource, from, to);

context 传入一个Content对象 ,

date  List<? extends Map<String, ?>>的集合;

from(new string[]{...}) 一个String类型的数组,该数组的元素为GridView的items;

to(new int[...]) 一个int数组,对应布局文件的控件资源ID,并且其顺序和上一个参数每一项一一对应。

二、下面是我结合聚合数据中的“菜谱大全"的数据做的一个菜单导航。

1、菜单分类的获取:

这里省略一些过程,聚合数据sdk需要在AndroidMainFest.xml进行配置,否则程序不能正确运行。关于聚合sdk的使用请查阅聚合数据官网文档。下面直接上代码。

  • 返回数据实体类FoodMenu:

     import java.util.ArrayList;
    
     public class FoodMenu {
    
         private int resultcode;//数据错误返回码
    private String reason;//数据错误原因
    private ArrayList<FirstFoodMenu >result;//返回数据
    public int getResultcode() {
    return resultcode;
    }
    public void setResultcode(int resultcode) {
    this.resultcode = resultcode;
    }
    public String getReason() {
    return reason;
    }
    public void setReason(String reason) {
    this.reason = reason;
    }
    public ArrayList<FirstFoodMenu> getResult() {
    return result;
    }
    public void setResult(ArrayList<FirstFoodMenu> result) {
    this.result = result;
    }
    }
  • 一级菜单实体类FirstFoodMenu

     package com.example.bean;
    
     import java.util.ArrayList;
    
     public class FirstFoodMenu {
    private String parentId;
    private String name;
    private ArrayList<SecondFoodMenu> list; public String getParentId() {
    return parentId;
    } public void setParentId(String parentId) {
    this.parentId = parentId;
    } public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } public ArrayList<SecondFoodMenu> getSecondFoodMenus() {
    return list;
    } public void setSecondFoodMenus(ArrayList<SecondFoodMenu> list) {
    this.list = list;
    }
    }
  • 二级菜单实体类SecondFoodMenu
     package com.example.bean;
    
     public class SecondFoodMenu {
    private int id;
    private String name;
    private int parentId; public int getId() {
    return id;
    } public void setId(int id) {
    this.id = id;
    } public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } public int getParentId() {
    return parentId;
    } public void setParentId(int parentId) {
    this.parentId = parentId;
    } @Override
    public String toString() {
    return "SecondFoodMenu [id=" + id + ", name=" + name + ", parentId=" + parentId + "]";
    } }
  • 数据分析类
     package com.example.parser;
    
     import org.json.JSONException;
    import org.json.JSONObject; public abstract class DataParser {
    protected String parserError(String s) {
    String result=null;
    try {
    JSONObject jsonObject = new JSONObject(s); int errorCode = jsonObject.getInt("error_code");
    if (isSuccess(errorCode)) {
    result= jsonObject.optString("result");
    if (result == null)
    return "{\"code\":0}";
    }
    } catch (JSONException e) {
    e.printStackTrace();
    }
    return result;
    } public abstract Object parser(String paramString, int paramInt); public abstract boolean isSuccess(int paramInt);
    }
  • 菜单分类分析器
     package com.example.parser;
    
     import java.util.ArrayList;
    import java.util.List;
    import com.example.bean.FirstFoodMenu;
    import com.google.gson.Gson;
    import com.google.gson.JsonSyntaxException;
    import com.google.gson.reflect.TypeToken;
    import android.content.Context;
    import android.widget.Toast; public class FoodMenuParser extends DataParser {
    private Context context; public FoodMenuParser(Context context) {
    this.context = context;
    } @SuppressWarnings("unchecked")
    @Override
    public List<FirstFoodMenu> parser(String s, int paramInt) {
    String result = parserError(s);
    try {
    if ((result != null) && (!result.equals(""))) {
    Gson gson = new Gson();
    return (List<FirstFoodMenu>) gson.fromJson(result, new TypeToken<List<FirstFoodMenu>>() {
    }.getType());
    }
    } catch (JsonSyntaxException e) {
    e.printStackTrace();
    }
    return null;
    }
    public String[][] secondParser(ArrayList<FirstFoodMenu> f){ return null; }
    @Override
    public boolean isSuccess(int errorCode) {
    // TODO Auto-generated method stub
    boolean b = false;
    switch (errorCode) {
    case 0:
    b = true;
    break;
    case 204601:
    Toast.makeText(this.context, "菜谱名称不能为空", 0).show();
    break;
    case 204602:
    Toast.makeText(this.context, "查询不到相关信息", 0).show();
    break;
    case 204603:
    Toast.makeText(this.context, "菜谱名过长", 0).show();
    break;
    case 204604:
    Toast.makeText(this.context, "错误的标签ID", 0).show();
    break;
    case 204605:
    Toast.makeText(this.context, "查询不到数据", 0).show();
    break;
    case 204606:
    Toast.makeText(this.context, "查询失败", 0).show();
    break;
    default:
    Toast.makeText(this.context, "查询失败", 0).show();
    break;
    } return b;
    } }
  • ExpandableListadapter适配器
     package com.example.adapter;
    
     import java.util.ArrayList;
    import java.util.HashMap; import com.example.lifecover.R;
    import android.content.Context;
    import android.graphics.Color;
    import android.graphics.drawable.ColorDrawable;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.AdapterView;
    import android.widget.BaseExpandableListAdapter;
    import android.widget.GridView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    import android.widget.SimpleAdapter;
    import android.widget.TextView;
    import android.widget.Toast; public class FoodMenuAdapter extends BaseExpandableListAdapter {
    Context context;
    private String[] group;
    private String[][] child;
    int[] group_state_array = new int[] { R.drawable.group_up, R.drawable.group_down };
    private LayoutInflater mInflater; public FoodMenuAdapter(Context context, String[] group, String[][] child) {
    mInflater = LayoutInflater.from(context);
    this.context = context;
    this.group = group;
    this.child = child;
    } @Override
    public int getGroupCount() {
    return group.length;
    } @Override
    public int getChildrenCount(int groupPosition) {
    return 1;
    } @Override
    public Object getGroup(int groupPosition) {
    return group[groupPosition];
    } @Override
    public Object getChild(int groupPosition, int childPosition) {
    // TODO Auto-generated method stub
    return null;
    } @Override
    public long getGroupId(int groupPosition) {
    // TODO Auto-generated method stub
    return groupPosition;
    } @Override
    public long getChildId(int groupPosition, int childPosition) {
    // TODO Auto-generated method stub
    return childPosition;
    } @Override
    public boolean hasStableIds() {
    return true;
    } /**
    * 显示:group
    */
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    // 为视图对象指定布局
    convertView = (LinearLayout) LinearLayout.inflate(context, R.layout.foodmenu_group_layout, null);
    RelativeLayout myLayout = (RelativeLayout) convertView.findViewById(R.id.group_layout);
    // 用来显示一级标签上的标题信息
    TextView group_title = (TextView) convertView.findViewById(R.id.group_title);
    // 用来显示一级标签上的大体描述的信息
    ImageView group_state = (ImageView) convertView.findViewById(R.id.group_state);
    // 设置标题上的文本信息
    group_title.setText(group[groupPosition]);
    // 设置整体描述上的文本信息 if (!isExpanded) {
    group_state.setBackgroundResource(group_state_array[0]);
    myLayout.setBackgroundResource(R.drawable.text_item_top_bg);
    } else {
    myLayout.setBackgroundResource(R.drawable.text_item_bg);
    group_state.setBackgroundResource(group_state_array[1]);
    } // 返回一个布局对象
    return convertView; } /**
    * 显示:child
    */
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
    ViewGroup parent) {
    // TODO Auto-generated method stub
    if (convertView == null) {
    mViewChild = new ViewChild();
    convertView = mInflater.inflate(R.layout.foodmenu_child_layout, null);
    mViewChild.gridView = (GridView) convertView.findViewById(R.id.channel_item_child_gridView);
    convertView.setTag(mViewChild);
    } else {
    mViewChild = (ViewChild) convertView.getTag();
    } SimpleAdapter mSimpleAdapter = new SimpleAdapter(context, setGridViewData(child[groupPosition]),
    R.layout.item_child_gridview, new String[] { "channel_gridview_item" },
    new int[] { R.id.channel_gridview_item });
    mViewChild.gridView.setAdapter(mSimpleAdapter);
    setGridViewListener(mViewChild.gridView);
    mViewChild.gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));
    return convertView;
    } ViewChild mViewChild; static class ViewChild {
    TextView textView;
    GridView gridView;
    } @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
    return false;
    } /**
    * 设置gridview点击事件监听
    *
    * @param gridView
    */
    private void setGridViewListener(final GridView gridView) {
    gridView.setOnItemClickListener(new GridView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // TODO Auto-generated method stub
    if (view instanceof TextView) {
    // 如果想要获取到哪一行,则自定义gridview的adapter,item设置2个textview一个隐藏设置id,显示哪一行
    TextView tv = (TextView) view;
    Toast.makeText(context, "position=" + position + "||" + tv.getText(), Toast.LENGTH_SHORT).show();
    Log.e("hefeng", "gridView listaner position=" + position + "||text=" + tv.getText());
    }
    }
    });
    } /**
    * 设置gridview数据
    *
    * @param data
    * @return
    */
    private ArrayList<HashMap<String, Object>> setGridViewData(String[] data) {
    ArrayList<HashMap<String, Object>> gridItem = new ArrayList<HashMap<String, Object>>();
    for (int i = 0; i < data.length; i++) {
    HashMap<String, Object> hashMap = new HashMap<String, Object>();
    hashMap.put("channel_gridview_item", data[i]);
    gridItem.add(hashMap);
    }
    return gridItem;
    } }
  • 重写GridView
    package com.example.view;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.widget.GridView; public class CustomGridView extends GridView { public CustomGridView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
    } @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
    MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
    }
    }
  • activity类
     package com.example.lifecover;
    
     import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.List; import com.example.adapter.FoodMenuAdapter;
    import com.example.bean.FirstFoodMenu;
    import com.example.bean.SecondFoodMenu;
    import com.example.parser.FoodMenuParser;
    import com.thinkland.sdk.android.DataCallBack;
    import com.thinkland.sdk.android.JuheData;
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.Context;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.ExpandableListView;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    import android.widget.ExpandableListView.OnGroupExpandListener; public class FoodActivity extends Activity implements OnClickListener {
    private ImageView iv_back;
    private TextView tv_title;
    private FoodActivity mContext;
    private Dialog loadingDialog;
    private String[] strings;// 一级菜单分类数组
    private String[] strings2;// 一级菜单分类id数组
    private String[][] strings3;// 二级菜单分类数组
    private ExpandableListView listView;
    private FoodMenuAdapter adapter; @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
    setContentView(R.layout.activity_food);
    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title);
    mContext = this;
    initView(); } private void showLoadingDialog() {
    if (this.loadingDialog != null) {
    this.loadingDialog.show();
    return;
    }
    this.loadingDialog = new Dialog(this.mContext, R.style.dialog_loading);
    View view = LayoutInflater.from(this.mContext).inflate(R.layout.dialog_loading, null);
    this.loadingDialog.setContentView(view, new ViewGroup.LayoutParams(-2, -1));
    this.loadingDialog.setCancelable(true);
    this.loadingDialog.show();
    } private void getFoodMenuData() {
    JuheData.executeWithAPI(mContext, 46, "http://apis.juhe.cn/cook/category", "get", null, new DataCallBack() { @Override
    public void onFailure(int arg0, String arg1, Throwable arg2) { Toast.makeText(mContext, "获取菜单分类信息失败,请检查网络!", Toast.LENGTH_LONG).show();
    } @Override
    public void onFinish() {
    loadingDialog.dismiss(); } @Override
    public void onSuccess(int arg0, String arg1) {
    save(arg1); }
    }); } public void save(String s) { try {
    FileOutputStream outfile = openFileOutput("current_file", Context.MODE_PRIVATE);
    outfile.write(s.getBytes());
    outfile.close();
    // Toast.makeText(this, "保存成功", 3000).show();
    } catch (Exception e) {
    // Toast.makeText(this, "保存失败", 3000).show();
    }
    } public String showData() {
    String content = "";
    try {
    FileInputStream showfile = openFileInput("current_file");
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] data = new byte[1024];
    int len = 0; while ((len = showfile.read(data)) != -1) {
    out.write(data, 0, len);
    }
    content = new String(out.toByteArray());
    // Toast.makeText(this, "显示成功", 3000).show();
    } catch (Exception e) {
    // Toast.makeText(this, "显示失败", 3000).show();
    }
    return content;
    } private void initView() {
    this.iv_back = (ImageView) findViewById(R.id.iv_back);
    this.iv_back.setVisibility(0);
    this.iv_back.setOnClickListener(this);
    this.tv_title = (TextView) findViewById(R.id.tv_title);
    this.tv_title.setText(R.string.food);
    listView = (ExpandableListView) findViewById(R.id.expandablelist);
    listView.setGroupIndicator(null);
    showLoadingDialog();
    String info = showData();
    if (info.isEmpty()) {
    getFoodMenuData();
    info = showData();
    } else {
    FoodMenuParser parser = new FoodMenuParser(FoodActivity.this.mContext);
    List<FirstFoodMenu> fMenus = parser.parser(info, 0);
    if (fMenus != null) {
    strings = new String[fMenus.size()];
    strings2 = new String[fMenus.size()];
    strings3 = new String[fMenus.size()][];// 初始化strings3[][]数组
    for (int i = 0; i < fMenus.size(); i++) {
    FirstFoodMenu fMenu = fMenus.get(i);
    strings[i] = fMenu.getName();
    strings2[i] = fMenu.getParentId();
    ArrayList<SecondFoodMenu> sMenus = fMenu.getSecondFoodMenus();
    strings3[i] = new String[sMenus.size()];
    for (int j = 0; j < sMenus.size(); j++) {
    strings3[i][j] = sMenus.get(j).getName();
    }
    }loadingDialog.dismiss();
    }
    adapter = new FoodMenuAdapter(mContext, strings, strings3);
    listView.setAdapter(adapter);
    listView.setOnGroupExpandListener(new OnGroupExpandListener() {
    @Override
    public void onGroupExpand(int groupPosition) {
    // TODO Auto-generated method stub
    for (int i = 0; i < adapter.getGroupCount(); i++) {
    if (groupPosition != i)
    listView.collapseGroup(i);
    }
    }
    }); }
    } @Override
    public void onClick(View v) {
    if (v.getId() == R.id.iv_back)
    finish();
    } }

    布局文件就贴上来了,如果在调试代码需要可以联系我。

以上是我在实训过程中做的第二个练手小Demo,下一个练手的是在这个基础上进行扩展:通过在菜单选择某一个菜肴,点击后可以看到这个菜的做的具体步骤。

利用ExpandableListView和gridview 显示可展开折叠菜单导航的更多相关文章

  1. jquery 展开折叠菜单

    jquery 展开折叠菜单 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <ht ...

  2. Vue+elementUI 自定义动态数据菜单导航组件实现展开收缩+路由跳转router-view渲染数据 路由跳转到同一个页面带参数ID 自动刷新数据

    准备:导入ElementUI 看官网教程 数据准备:JSON数据转换成树状 参考文章: JS实现 JSON扁平数据转换树状数据 后台我拿的数据是这样的格式: [ {id:1 , parentId: 0 ...

  3. React+Ant Design设置左侧菜单导航路由的显示与隐藏(与权限无关)

    最近在学习react时,用到了很流行的UI框架Ant Design,也了解了一下Ant Design Pro,发现它们都有导航组件,Ant Design框架的导航菜单在这里,Ant Design Pr ...

  4. jquery垂直展开折叠手风琴二级菜单

    摘要:jquery实现垂直展开二级菜单 最近新开发一个简单项目,用到左侧两级的菜单.找找了手头的文件,竟然没有现成的代码,算了,去网上找找整理下吧. 注:jquery-1.8.3.min.js需要下载 ...

  5. android 项目学习随笔十七(ListView、GridView显示组图)

    ListView.GridView显示组图,处理机制相同 <?xml version="1.0" encoding="utf-8"?> <Li ...

  6. Pivot Table系列之展开/折叠用法 (Expand/Collapse)

    1.遇到的问题: PivotTable中本来已经展开的维度的Hierarchy(层次结构),在切换切片器的数据集时,层次结构就折叠在一起了:没有按照之前的方式展开显示. 2.在做成PivotTable ...

  7. JS点击查看更多内容 控制段落文字展开折叠

    JavaScript+jQuery实现的文字展开折叠效果,点击文字后文字内容会完整的显示出来,控制段落来显示文字,不需要的时候,可以再次点击后将内容折叠起来,也就是隐藏了一部分内容.点击查看更多的功能 ...

  8. javascript实现列表的点击展开折叠

    <script> window.onload = function() { //要折叠的区域 var catalog = document.getElementById("div ...

  9. js 控制展开折叠 div html dom

    js 控制展开折叠 div    html dom <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ...

随机推荐

  1. 终于吧Appserv搞通了

    .在学习php的时候遇到了这个问题; 1.Fatal error: Call to undefined function set_magic_quotes_runtime() in E:\App 打开 ...

  2. Unity3D之Legacy动画系统学习笔记

    Unity3D的Mecanim动画系统是非常强大的,而且作为Unity推荐的动画系统,其未来会完全代替老的一套动画系统,即Legacy动画系统.目前的情况是Mecanim与Legacy两套动画系统同时 ...

  3. Unity3D之Mecanim动画系统学习笔记(六):使用脚本控制动画

    控制人物动画播放 这里我重新弄了一个简单的场景和新的Animator Controller来作为示例. 下面先看看Animator Controller的配置: 人物在站立状态只能进入走路,走路只能进 ...

  4. Codeforces Round #219 (Div. 1)(完全)

    戳我看题目 A:给你n个数,要求尽可能多的找出匹配,如果两个数匹配,则ai*2 <= aj 排序,从中间切断,分成相等的两半后,对于较大的那一半,从大到小遍历,对于每个数在左边那组找到最大的满足 ...

  5. win8图片默认不显示

    最近,发现了一个问题,在查看图片的时候,出现了这样的情况: 查看的时候很不方便,想要找到自己需要的图片就要误打误撞,也不知道自己在哪儿设置了,于是,上网查资料,才发现其实只需要简单的该一下设置就可以了 ...

  6. map的正确删除方式

    遍历删除map元素的正确方式是 for(itor = maptemplate.begin; itor != maptemplate.end(); ) {      if(neederase)     ...

  7. HCTF2016-杂项签到

    题目下载了一个+_+.pcapng ,用Wireshark打开, Ctrl-F搜索flag 发现python代码 将Data导出 #!/usr/bin/env python # coding:utf- ...

  8. 检测到有潜在危险的 Request.Form

    今天在做一个.net的新闻发布器的时候. 遇到这样的一个问,在html编辑器里面加入图片提交的时候 就报一个 从客户端(content1="<img src="/web/ne ...

  9. mysqldump的流程

    发布时间:2013 年 4 月 6 日 发布者: OurMySQL 来源:P.Linux Laboratory      前几天看到群里在讨论mysqldump导致锁表的问题,为什么一个表已经dump ...

  10. 第2章 数字之魅——斐波那契(Fibonacci)数列

    斐波那契(Fibonacci)数列 问题描述 递归算法: package chapter2shuzizhimei.fibonacci; /** * Fibonacci数列递归求解 * @author ...