原文链接:http://blog.csdn.net/duguju/article/details/49538341

有时我们需要用GridView显示目录列表,有时甚至是二级的,即listview每一个item里面又各自嵌入一个gridview,但是当二级目录(数据条目)的数量过多时,界面会比较臃肿,这时我们就想要有类似展开与折叠的效果,作者采用的策略是数据分段的分别显示,其中对于显示边界(处于限制显示数目的特定位置)的控件要有数据的动态更新和点击判断操作。效果如图:

具体实现:

一、Activity界面

  1. package com.example.gridinlist;
  2. import java.util.Vector;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.widget.ListView;
  6. public class MainActivity extends Activity {
  7. private ListView listView;
  8. private MyAdapter adapter;
  9. private Vector<String> stringVector = new Vector<String>();
  10. @Override
  11. protected void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. initView();
  15. }
  16. private void initView() {
  17. listView = (ListView) findViewById(R.id.list);
  18. adapter = new MyAdapter(this, this.getLayoutInflater(), stringVector);
  19. stringVector.add("0");
  20. stringVector.add("1");
  21. stringVector.add("2");
  22. stringVector.add("3");
  23. stringVector.add("4");
  24. stringVector.add("5");
  25. listView.setAdapter(adapter);
  26. }
  27. }

主Activity,里面只有一个textview(标题)和listview(主体),其中Listview的适配器MyAdapter是自写的(也是实现效果的主要逻辑代码)。

这里我们直传给MyAdapter一个字符串向量,为了简便,不管一级还是二级目录都是用的这一个向量(实际中每个二级子向量应该都是不同的),用户可根据需求自行添加或修改(也可以使用Parcel将其封装为一个二级的数据类型,具体不再赘述)。

Activity布局文件

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context="${relativePackage}.${activityClass}" >
  6. <TextView
  7. android:id="@+id/title"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:gravity="center_horizontal"
  11. android:layout_centerHorizontal="true"
  12. android:text="@string/hello_world" />
  13. <ListView
  14. android:id="@+id/list"
  15. android:layout_width="fill_parent"
  16. android:layout_height="fill_parent"
  17. android:layout_marginLeft="7dip"
  18. android:layout_marginRight="7dip"
  19. android:layout_marginBottom="7dip"
  20. android:layout_below="@+id/title"
  21. android:cacheColorHint="#00000000"
  22. android:drawSelectorOnTop="false"
  23. android:listSelector="#00000000"
  24. android:scrollbars="none"
  25. android:scrollingCache="true"
  26. android:drawingCacheQuality="low"
  27. android:divider="#00000000"
  28. android:dividerHeight="0dip"
  29. android:fadingEdgeLength="0.0sp"
  30. />
  31. </RelativeLayout>

二、自写的istview的Adapter(关键代码)

  1. package com.example.gridinlist;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.Vector;
  5. import android.annotation.SuppressLint;
  6. import android.content.Context;
  7. import android.database.DataSetObserver;
  8. import android.util.Log;
  9. import android.view.LayoutInflater;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.AdapterView;
  13. import android.widget.AdapterView.OnItemClickListener;
  14. import android.widget.BaseAdapter;
  15. import android.widget.GridView;
  16. import android.widget.SimpleAdapter;
  17. import android.widget.TextView;
  18. import android.widget.Toast;
  19. public class MyAdapter extends BaseAdapter
  20. {
  21. private static final String TAG = "MyAdapter";
  22. private LayoutInflater inflater;
  23. private Context context;
  24. private Vector<String> vector;
  25. private int numGridShowLimit = 4; //Gridview限定显示数目
  26. /**
  27. * 搜索Adapter初始化
  28. */
  29. public MyAdapter(Context context,LayoutInflater inflater,Vector<String> vector)
  30. {
  31. this.context = context;
  32. this.inflater = inflater;
  33. this.vector = vector;
  34. }
  35. /**
  36. * 初始化View
  37. */
  38. private static class ViewHolder
  39. {
  40. private TextView  titleTextView;
  41. private GridView  contentGridView;
  42. private GridView  contentMoreGridView;
  43. }
  44. /**
  45. * 添加数据
  46. */
  47. @SuppressLint("InflateParams")
  48. @Override
  49. public View getView(int position, View convertView, ViewGroup parent)
  50. {
  51. final ViewHolder viewHolder;
  52. if( convertView == null )
  53. {
  54. convertView = inflater.inflate(R.layout.adapter_listview,null);
  55. viewHolder = new ViewHolder();
  56. viewHolder.titleTextView  = (TextView) convertView.findViewById(R.id.list_txt_title);
  57. viewHolder.contentGridView = (GridView) convertView.findViewById(R.id.list_grid);
  58. viewHolder.contentMoreGridView = (GridView) convertView.findViewById(R.id.list_grid_more);
  59. convertView.setTag(viewHolder);
  60. }
  61. else viewHolder = (ViewHolder) convertView.getTag();
  62. try
  63. {
  64. if(vector != null && vector.size() > 0)
  65. {
  66. final String category = vector.get(position);
  67. if(category != null)
  68. {
  69. viewHolder.titleTextView.setText("list item "+category);
  70. }
  71. if (vector.size() > 0) {
  72. final ArrayList<HashMap<String, Object>> categoryList = new ArrayList<HashMap<String, Object>>();
  73. final ArrayList<HashMap<String, Object>> categorySubList1 = new ArrayList<HashMap<String, Object>>();
  74. final ArrayList<HashMap<String, Object>> categorySubList2 = new ArrayList<HashMap<String, Object>>();
  75. //先封装整个数据向量到categoryList
  76. if (vector != null && vector.size() > 0) {
  77. for (int i = 0; i < vector.size(); i++) {
  78. String o = vector.get(i);
  79. if (o != null) {
  80. HashMap<String, Object> map = new HashMap<String, Object>();
  81. map.put("ItemText", "grid" + o);
  82. categoryList.add(map);
  83. }
  84. }
  85. }
  86. final int mypos = position;
  87. //当数据向量长度大于限定显示的grid数目时,将整个数据向量分成两段
  88. if (vector.size() > numGridShowLimit) {
  89. //封装前段数据到categorySubList1
  90. for (int i = 0; i < numGridShowLimit; i++) {
  91. String o = vector.get(i);
  92. if (o != null) {
  93. if (i==numGridShowLimit-1) {
  94. HashMap<String, Object> map = new HashMap<String, Object>();
  95. if (viewHolder.contentMoreGridView.getVisibility()==View.GONE) {
  96. //若处于折叠状态则将限定数目的位置的数据修改为“+”(用于点击展开)
  97. map.put("ItemText", "" + "+");
  98. }else {
  99. //若处于展开状态则限定数目的位置的数据正常显示
  100. map.put("ItemText", "grid" + o);
  101. }
  102. categorySubList1.add(map);
  103. }else {
  104. HashMap<String, Object> map = new HashMap<String, Object>();
  105. map.put("ItemText", "grid" + o);
  106. categorySubList1.add(map);
  107. }
  108. }
  109. }
  110. //封装后段数据到categorySubList2
  111. for (int i = numGridShowLimit; i < vector.size(); i++) {
  112. String o = vector.get(i);
  113. if (o != null) {
  114. HashMap<String, Object> map = new HashMap<String, Object>();
  115. map.put("ItemText", "grid" + o);
  116. categorySubList2.add(map);
  117. }
  118. }
  119. HashMap<String, Object> map = new HashMap<String, Object>();
  120. map.put("ItemText", "-"); //在第二段的最后添加一个“-”数据(用于点击折叠)
  121. categorySubList2.add(map);
  122. //创建第一部分GridView的adapter
  123. final SimpleAdapter simpleAdapter1 = new SimpleAdapter(context, categorySubList1,
  124. R.layout.adapter_gridview,
  125. new String[] { "ItemText" }, // 对应map的Key
  126. new int[] { R.id.ItemText }); // 对应R的Id
  127. viewHolder.contentGridView.setAdapter(simpleAdapter1);
  128. //创建第二部分GridView的adapter
  129. final SimpleAdapter simpleAdapter2 = new SimpleAdapter(context, categorySubList2,
  130. R.layout.adapter_gridview,
  131. new String[] { "ItemText" }, // 对应map的Key
  132. new int[] { R.id.ItemText }); // 对应R的Id
  133. viewHolder.contentMoreGridView.setAdapter(simpleAdapter2);
  134. //设置第二部分GridView的adapter中的具体item点击事件
  135. viewHolder.contentMoreGridView.setOnItemClickListener(new OnItemClickListener() {
  136. public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) {
  137. if (categoryList.size()>numGridShowLimit && pos==categoryList.size()-numGridShowLimit) {
  138. //若点击末尾的“-”,则将gridview折叠,并修改第一部分最后位置为“+”(可展开状态)
  139. View rel =  (View) viewHolder.contentGridView.getChildAt(numGridShowLimit-1);
  140. TextView tv =  (TextView) rel.findViewById(R.id.ItemText);
  141. tv.setText("+");
  142. viewHolder.contentMoreGridView.setVisibility(View.GONE);
  143. }else {
  144. view.setTag(mypos*100+numGridShowLimit+pos);
  145. Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
  146. }
  147. }
  148. });
  149. }
  150. else {
  151. //若数据向量数目不大于限定的显示数目,则正常创建第一部分GridView的adapter(直接使用整体数据categoryList)
  152. final SimpleAdapter simpleAdapter = new SimpleAdapter(context, categoryList,
  153. R.layout.adapter_gridview,
  154. new String[] { "ItemText" }, // 对应map的Key
  155. new int[] { R.id.ItemText }); // 对应R的Id
  156. viewHolder.contentGridView.setAdapter(simpleAdapter);
  157. }
  158. //设置第一部分GridView的adapter中的具体item点击事件
  159. viewHolder.contentGridView.setOnItemClickListener(new OnItemClickListener() {
  160. public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) {
  161. if (categoryList.size()>numGridShowLimit && pos==numGridShowLimit-1) {
  162. TextView tv =  (TextView) view.findViewById(R.id.ItemText);
  163. String content = tv.getText().toString();
  164. if (content.equals("+")) {
  165. //若点击“+”,则进行展开操作,即显示第二部分gridview,并修改最后位置为“+”
  166. tv.setText("grid"+vector.get(numGridShowLimit-1));
  167. viewHolder.contentMoreGridView.setVisibility(View.VISIBLE);
  168. }else {
  169. view.setTag(mypos*100+pos);
  170. Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
  171. }
  172. }else {
  173. view.setTag(mypos*100+pos);
  174. Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
  175. }
  176. }
  177. });
  178. }
  179. }
  180. }
  181. catch (Exception e)
  182. {
  183. e.printStackTrace();
  184. Log.e(TAG, "Exception");
  185. }
  186. return convertView;
  187. }
  188. @Override
  189. public int getCount()
  190. {
  191. return vector.size();
  192. }
  193. @Override
  194. public Object getItem(int position) {
  195. return null;
  196. }
  197. @Override
  198. public long getItemId(int position) {
  199. return 0;
  200. }
  201. @Override
  202. public void unregisterDataSetObserver(DataSetObserver observer)
  203. {
  204. if (observer != null) {
  205. super.unregisterDataSetObserver(observer);
  206. }
  207. }
  208. }

具体步骤请看代码中的注释,需要注意的是,里面的GridView使用的是自写的控件,因为若使用Android自带的GridView,会出现在ListView中只显示一行grid的情况,这是因为ListView无法动态获取GridView的数目而无法确定它的高度,因此默认认为只有一行数据。

解决方法是:在自写的GridView里面,需要重写onMeasure方法,这样就可以得到GridView的高度了,代码如下:

  1. package com.example.gridinlist;
  2. import android.widget.GridView;
  3. public class MyGridView extends GridView
  4. {
  5. public MyGridView(android.content.Context context,
  6. android.util.AttributeSet attrs)
  7. {
  8. super(context, attrs);
  9. }
  10. /**
  11. * 重写的onMeasure方法
  12. */
  13. public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  14. {
  15. int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
  16. MeasureSpec.AT_MOST);
  17. super.onMeasure(widthMeasureSpec, expandSpec);
  18. }
  19. }

ListView的item布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="wrap_content"
  6. android:layout_marginTop="1dip"
  7. android:layout_marginBottom="1dip"
  8. android:orientation="vertical"
  9. android:baselineAligned="false"
  10. android:background="#ffffff"
  11. >
  12. <RelativeLayout
  13. android:id="@+id/list_rel"
  14. android:layout_width="fill_parent"
  15. android:layout_height="wrap_content"
  16. android:layout_marginTop="10dip"
  17. android:layout_marginBottom="10dip"
  18. >
  19. <ImageView
  20. android:id="@+id/list_img_icon"
  21. android:layout_width="3dip"
  22. android:layout_height="17dip"
  23. android:layout_marginLeft="15dip"
  24. android:contentDescription="@null"
  25. android:scaleType="fitXY"
  26. android:layout_centerVertical="true"
  27. android:src="@drawable/selected_orange"
  28. android:visibility="visible" />
  29. <TextView
  30. android:id="@+id/list_txt_title"
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:layout_toRightOf="@+id/list_img_icon"
  34. android:layout_marginLeft="7dip"
  35. android:layout_marginRight="7dip"
  36. android:gravity="center"
  37. android:layout_centerVertical="true"
  38. android:singleLine="true"
  39. />
  40. </RelativeLayout>
  41. <com.example.gridinlist.MyGridView
  42. android:id="@+id/list_grid"
  43. android:layout_width="fill_parent"
  44. android:layout_height="fill_parent"
  45. android:layout_marginBottom="1dip"
  46. android:columnWidth="70dip"
  47. android:horizontalSpacing="10dip"
  48. android:verticalSpacing="10dip"
  49. android:listSelector="@android:color/transparent"
  50. android:numColumns="4"
  51. android:paddingLeft="15dip"
  52. android:paddingRight="15dip"
  53. android:scrollbars="none"
  54. android:stretchMode="columnWidth"
  55. android:visibility="visible" >
  56. </com.example.gridinlist.MyGridView>
  57. <com.example.gridinlist.MyGridView
  58. android:id="@+id/list_grid_more"
  59. android:layout_width="fill_parent"
  60. android:layout_height="fill_parent"
  61. android:layout_marginTop="10dip"
  62. android:layout_marginBottom="1dip"
  63. android:columnWidth="70dip"
  64. android:horizontalSpacing="10dip"
  65. android:verticalSpacing="10dip"
  66. android:listSelector="@android:color/transparent"
  67. android:numColumns="4"
  68. android:paddingLeft="15dip"
  69. android:paddingRight="15dip"
  70. android:scrollbars="none"
  71. android:stretchMode="columnWidth"
  72. android:visibility="gone" >
  73. </com.example.gridinlist.MyGridView>
  74. </LinearLayout>

里面包含一个标题,以及两个自写的GridView(一个显示前面部分,另一个显示剩下的,点击展开与折叠其实就是第二个GridView的显示与隐藏)

GridView的item布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5. <TextView
  6. android:id="@+id/ItemText"
  7. android:layout_width="70dip"
  8. android:layout_height="32dip"
  9. android:background="@drawable/btn_txt_bg"
  10. android:text=""
  11. android:gravity="center"
  12. />
  13. </RelativeLayout>

只是简单的一个TextView,用户想扩展或丰富可自行修改。

代码下载连接:http://download.csdn.net/detail/duguju/9233759

listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠的更多相关文章

  1. ListView嵌套GridView显示不完整的解决方案

    转载注明出处:http://blog.csdn.net/allen315410/article/details/40152987 近期在做项目中,有个模块须要在ListView中嵌套一个GridVie ...

  2. Flutter中用ListView嵌套GridView报错异常

    flutter中的ListView组件和GridView组件都是常用的布局组件,有时候ListView中需要嵌套GridView来使用,例如下图: 这种情况就需要在ListView里面再嵌套一个Gri ...

  3. android listView嵌套gridview的使用心得

    在开发的过程中可能需要用到listview嵌套gridview的场景,但是在Android中, 不能在一个拥有Scrollbar的组件中嵌入另一个拥有Scrollbar的组件,因为这不科学,会混淆滑动 ...

  4. ScrollView嵌套ListView嵌套GridView的上下拉以及加载更多

    ScrollView 效果 ScrollView 说明 一个ScrollView 嵌套ListView 嵌套GridView的上拉加载更多,下拉刷新的demo. 主要是重写了GridView和Lsit ...

  5. ListView嵌套GridView

    首先,我们通过两个实例来了解下本篇文章所讲的重点,看下图: 微博: 陌陌: 大家应该对这两款软件并不陌生,接下来,我将列举下本文将要实现的几个点: 1.ListView嵌套GridView,互不冲突, ...

  6. ListView嵌套GridView,显示不全解决办法

    ListView嵌套GridView时,遇到了GridView只显示一行,其余都显示不出来的问题,最终解决办法如下: 需要自定义GridView,重新绘制高度即可: public class MyGr ...

  7. ListView嵌套GridView使用详解及注意事项

    ListView嵌套GridView即ListView的每个Item中都包含一个GridView:需要注意的是由于ListView和GridView都是可滑动的控件. 所以需要自定义GridView, ...

  8. 【Android】listview 嵌套gridview报错,代码:”during second layout pass: posting in next frame

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985, QQ986945193 公众号:程序员小冰 说明:本人曾经在listview嵌套gridview出现 ...

  9. Android中ListView嵌套GridView的简单消息流UI(解决宽高问题)

    最近搞一个项目,需要用到类似于新浪微博的消息流,即每一项有文字.有九宫格图片,因此这就涉及到ListView或者ScrollView嵌套GridView的问题.其中GridView的高度问题在网上都很 ...

随机推荐

  1. RBAC基于角色的访问控制

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...

  2. MFC 文件夹选择对话框

    CString setSavePath() { CString strPath = _T(""); HRESULT hr; LPITEMIDLIST pItemList; BROW ...

  3. JS技巧

    2016-08-09 200多个js技巧代码(Down) word下载 200多个js技巧代码 目录 1.文本框焦点问题... 6 2.网页按钮的特殊颜色... 6 3.鼠标移入移出时颜色变化... ...

  4. RANSAC算法笔记

    最近在做平面拟合,待处理的数据中有部分噪点需要去除,很多论文中提到可以使用Ransac方法来去除噪点. 之前在做图像配准时,用到了Ransac算法,但是没有去仔细研究,现在好好研究一番. 参考: ht ...

  5. 浩瀚PDA开单器-结束手工开单模式【百货、商超】PDA安卓智能手持POS 进销存管理系统移动收银管理软件

    移动销售终端:先进的跨平台技术,支持智能PDA等移动终端提供移动销售开单.移动POS.移动查询货品.移动盘点等功能. 移动开单器的操作说明 第一步:选客户 Ø        用户在空白开单主页左划屏幕 ...

  6. log4j:WARN Please initialize the log4j system properly 问题解决

    log4j:WARN No appenders could be found for logger (com.netease.qa.testng.TestngRetry).log4j:WARN Ple ...

  7. BestCoder#51

    #include <cstdio> #include <iostream> #include <cmath> #include <cstring> us ...

  8. 530 User cannot log in, home directory inaccessible.

    服务器是winserver,控制面板-用户账号里新建了一个Ftp账户用来做ftp连接.可在本地连接FTP总提示530 User cannot log in, home directory inacce ...

  9. bzoj1927最小费用最大流

    其实本来打算做最小费用最大流的题目前先来点模板题的,,,结果看到这道题二话不说(之前打太多了)敲了一个dinic,快写完了发现不对 我当时就这表情→   =_=你TM逗我 刚要删突然感觉dinic的模 ...

  10. javascript中三种典型情况下this的含义

    this本意:基于函数的执行环境绑定. 1)一般函数内部,返回的是window(作用域链中的第二层全局作用域) function test() { return this; } alert(test( ...