首页 > 代码库 > listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠
listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠
原文链接:http://blog.csdn.net/duguju/article/details/49538341
有时我们需要用GridView显示目录列表,有时甚至是二级的,即listview每一个item里面又各自嵌入一个gridview,但是当二级目录(数据条目)的数量过多时,界面会比较臃肿,这时我们就想要有类似展开与折叠的效果,作者采用的策略是数据分段的分别显示,其中对于显示边界(处于限制显示数目的特定位置)的控件要有数据的动态更新和点击判断操作。效果如图:
具体实现:
一、Activity界面
- package com.example.gridinlist;
- import java.util.Vector;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ListView;
- public class MainActivity extends Activity {
- private ListView listView;
- private MyAdapter adapter;
- private Vector<String> stringVector = new Vector<String>();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- }
- private void initView() {
- listView = (ListView) findViewById(R.id.list);
- adapter = new MyAdapter(this, this.getLayoutInflater(), stringVector);
- stringVector.add("0");
- stringVector.add("1");
- stringVector.add("2");
- stringVector.add("3");
- stringVector.add("4");
- stringVector.add("5");
- listView.setAdapter(adapter);
- }
- }
主Activity,里面只有一个textview(标题)和listview(主体),其中Listview的适配器MyAdapter是自写的(也是实现效果的主要逻辑代码)。
这里我们直传给MyAdapter一个字符串向量,为了简便,不管一级还是二级目录都是用的这一个向量(实际中每个二级子向量应该都是不同的),用户可根据需求自行添加或修改(也可以使用Parcel将其封装为一个二级的数据类型,具体不再赘述)。
Activity布局文件
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="${relativePackage}.${activityClass}" >
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:layout_centerHorizontal="true"
- android:text="@string/hello_world" />
- <ListView
- android:id="@+id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginLeft="7dip"
- android:layout_marginRight="7dip"
- android:layout_marginBottom="7dip"
- android:layout_below="@+id/title"
- android:cacheColorHint="#00000000"
- android:drawSelectorOnTop="false"
- android:listSelector="#00000000"
- android:scrollbars="none"
- android:scrollingCache="true"
- android:drawingCacheQuality="low"
- android:divider="#00000000"
- android:dividerHeight="0dip"
- android:fadingEdgeLength="0.0sp"
- />
- </RelativeLayout>
二、自写的istview的Adapter(关键代码)
- package com.example.gridinlist;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Vector;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.database.DataSetObserver;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.BaseAdapter;
- import android.widget.GridView;
- import android.widget.SimpleAdapter;
- import android.widget.TextView;
- import android.widget.Toast;
- public class MyAdapter extends BaseAdapter
- {
- private static final String TAG = "MyAdapter";
- private LayoutInflater inflater;
- private Context context;
- private Vector<String> vector;
- private int numGridShowLimit = 4; //Gridview限定显示数目
- /**
- * 搜索Adapter初始化
- */
- public MyAdapter(Context context,LayoutInflater inflater,Vector<String> vector)
- {
- this.context = context;
- this.inflater = inflater;
- this.vector = vector;
- }
- /**
- * 初始化View
- */
- private static class ViewHolder
- {
- private TextView titleTextView;
- private GridView contentGridView;
- private GridView contentMoreGridView;
- }
- /**
- * 添加数据
- */
- @SuppressLint("InflateParams")
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- final ViewHolder viewHolder;
- if( convertView == null )
- {
- convertView = inflater.inflate(R.layout.adapter_listview,null);
- viewHolder = new ViewHolder();
- viewHolder.titleTextView = (TextView) convertView.findViewById(R.id.list_txt_title);
- viewHolder.contentGridView = (GridView) convertView.findViewById(R.id.list_grid);
- viewHolder.contentMoreGridView = (GridView) convertView.findViewById(R.id.list_grid_more);
- convertView.setTag(viewHolder);
- }
- else viewHolder = (ViewHolder) convertView.getTag();
- try
- {
- if(vector != null && vector.size() > 0)
- {
- final String category = vector.get(position);
- if(category != null)
- {
- viewHolder.titleTextView.setText("list item "+category);
- }
- if (vector.size() > 0) {
- final ArrayList<HashMap<String, Object>> categoryList = new ArrayList<HashMap<String, Object>>();
- final ArrayList<HashMap<String, Object>> categorySubList1 = new ArrayList<HashMap<String, Object>>();
- final ArrayList<HashMap<String, Object>> categorySubList2 = new ArrayList<HashMap<String, Object>>();
- //先封装整个数据向量到categoryList
- if (vector != null && vector.size() > 0) {
- for (int i = 0; i < vector.size(); i++) {
- String o = vector.get(i);
- if (o != null) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("ItemText", "grid" + o);
- categoryList.add(map);
- }
- }
- }
- final int mypos = position;
- //当数据向量长度大于限定显示的grid数目时,将整个数据向量分成两段
- if (vector.size() > numGridShowLimit) {
- //封装前段数据到categorySubList1
- for (int i = 0; i < numGridShowLimit; i++) {
- String o = vector.get(i);
- if (o != null) {
- if (i==numGridShowLimit-1) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- if (viewHolder.contentMoreGridView.getVisibility()==View.GONE) {
- //若处于折叠状态则将限定数目的位置的数据修改为“+”(用于点击展开)
- map.put("ItemText", "" + "+");
- }else {
- //若处于展开状态则限定数目的位置的数据正常显示
- map.put("ItemText", "grid" + o);
- }
- categorySubList1.add(map);
- }else {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("ItemText", "grid" + o);
- categorySubList1.add(map);
- }
- }
- }
- //封装后段数据到categorySubList2
- for (int i = numGridShowLimit; i < vector.size(); i++) {
- String o = vector.get(i);
- if (o != null) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("ItemText", "grid" + o);
- categorySubList2.add(map);
- }
- }
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("ItemText", "-"); //在第二段的最后添加一个“-”数据(用于点击折叠)
- categorySubList2.add(map);
- //创建第一部分GridView的adapter
- final SimpleAdapter simpleAdapter1 = new SimpleAdapter(context, categorySubList1,
- R.layout.adapter_gridview,
- new String[] { "ItemText" }, // 对应map的Key
- new int[] { R.id.ItemText }); // 对应R的Id
- viewHolder.contentGridView.setAdapter(simpleAdapter1);
- //创建第二部分GridView的adapter
- final SimpleAdapter simpleAdapter2 = new SimpleAdapter(context, categorySubList2,
- R.layout.adapter_gridview,
- new String[] { "ItemText" }, // 对应map的Key
- new int[] { R.id.ItemText }); // 对应R的Id
- viewHolder.contentMoreGridView.setAdapter(simpleAdapter2);
- //设置第二部分GridView的adapter中的具体item点击事件
- viewHolder.contentMoreGridView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) {
- if (categoryList.size()>numGridShowLimit && pos==categoryList.size()-numGridShowLimit) {
- //若点击末尾的“-”,则将gridview折叠,并修改第一部分最后位置为“+”(可展开状态)
- View rel = (View) viewHolder.contentGridView.getChildAt(numGridShowLimit-1);
- TextView tv = (TextView) rel.findViewById(R.id.ItemText);
- tv.setText("+");
- viewHolder.contentMoreGridView.setVisibility(View.GONE);
- }else {
- view.setTag(mypos*100+numGridShowLimit+pos);
- Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- else {
- //若数据向量数目不大于限定的显示数目,则正常创建第一部分GridView的adapter(直接使用整体数据categoryList)
- final SimpleAdapter simpleAdapter = new SimpleAdapter(context, categoryList,
- R.layout.adapter_gridview,
- new String[] { "ItemText" }, // 对应map的Key
- new int[] { R.id.ItemText }); // 对应R的Id
- viewHolder.contentGridView.setAdapter(simpleAdapter);
- }
- //设置第一部分GridView的adapter中的具体item点击事件
- viewHolder.contentGridView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) {
- if (categoryList.size()>numGridShowLimit && pos==numGridShowLimit-1) {
- TextView tv = (TextView) view.findViewById(R.id.ItemText);
- String content = tv.getText().toString();
- if (content.equals("+")) {
- //若点击“+”,则进行展开操作,即显示第二部分gridview,并修改最后位置为“+”
- tv.setText("grid"+vector.get(numGridShowLimit-1));
- viewHolder.contentMoreGridView.setVisibility(View.VISIBLE);
- }else {
- view.setTag(mypos*100+pos);
- Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
- }
- }else {
- view.setTag(mypos*100+pos);
- Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- Log.e(TAG, "Exception");
- }
- return convertView;
- }
- @Override
- public int getCount()
- {
- return vector.size();
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public void unregisterDataSetObserver(DataSetObserver observer)
- {
- if (observer != null) {
- super.unregisterDataSetObserver(observer);
- }
- }
- }
具体步骤请看代码中的注释,需要注意的是,里面的GridView使用的是自写的控件,因为若使用Android自带的GridView,会出现在ListView中只显示一行grid的情况,这是因为ListView无法动态获取GridView的数目而无法确定它的高度,因此默认认为只有一行数据。
解决方法是:在自写的GridView里面,需要重写onMeasure方法,这样就可以得到GridView的高度了,代码如下:
- package com.example.gridinlist;
- import android.widget.GridView;
- public class MyGridView extends GridView
- {
- public MyGridView(android.content.Context context,
- android.util.AttributeSet attrs)
- {
- super(context, attrs);
- }
- /**
- * 重写的onMeasure方法
- */
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
- MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
- }
ListView的item布局文件:
- <?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:layout_marginTop="1dip"
- android:layout_marginBottom="1dip"
- android:orientation="vertical"
- android:baselineAligned="false"
- android:background="#ffffff"
- >
- <RelativeLayout
- android:id="@+id/list_rel"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
- android:layout_marginBottom="10dip"
- >
- <ImageView
- android:id="@+id/list_img_icon"
- android:layout_width="3dip"
- android:layout_height="17dip"
- android:layout_marginLeft="15dip"
- android:contentDescription="@null"
- android:scaleType="fitXY"
- android:layout_centerVertical="true"
- android:src=http://www.mamicode.com/"@drawable/selected_orange"
- android:visibility="visible" />
- <TextView
- android:id="@+id/list_txt_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/list_img_icon"
- android:layout_marginLeft="7dip"
- android:layout_marginRight="7dip"
- android:gravity="center"
- android:layout_centerVertical="true"
- android:singleLine="true"
- />
- </RelativeLayout>
- <com.example.gridinlist.MyGridView
- android:id="@+id/list_grid"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginBottom="1dip"
- android:columnWidth="70dip"
- android:horizontalSpacing="10dip"
- android:verticalSpacing="10dip"
- android:listSelector="@android:color/transparent"
- android:numColumns="4"
- android:paddingLeft="15dip"
- android:paddingRight="15dip"
- android:scrollbars="none"
- android:stretchMode="columnWidth"
- android:visibility="visible" >
- </com.example.gridinlist.MyGridView>
- <com.example.gridinlist.MyGridView
- android:id="@+id/list_grid_more"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginTop="10dip"
- android:layout_marginBottom="1dip"
- android:columnWidth="70dip"
- android:horizontalSpacing="10dip"
- android:verticalSpacing="10dip"
- android:listSelector="@android:color/transparent"
- android:numColumns="4"
- android:paddingLeft="15dip"
- android:paddingRight="15dip"
- android:scrollbars="none"
- android:stretchMode="columnWidth"
- android:visibility="gone" >
- </com.example.gridinlist.MyGridView>
- </LinearLayout>
里面包含一个标题,以及两个自写的GridView(一个显示前面部分,另一个显示剩下的,点击展开与折叠其实就是第二个GridView的显示与隐藏)
GridView的item布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <TextView
- android:id="@+id/ItemText"
- android:layout_width="70dip"
- android:layout_height="32dip"
- android:background="@drawable/btn_txt_bg"
- android:text=""
- android:gravity="center"
- />
- </RelativeLayout>
只是简单的一个TextView,用户想扩展或丰富可自行修改。
代码下载连接:http://download.csdn.net/detail/duguju/9233759
listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠