您的位置:首页 > 移动开发 > Android开发

ListView中能嵌套使用'GridView'吗?

2015-09-28 23:24 549 查看
在做app的时候或许都会遇到这样的需求,在一个ListView中显示类似GridView的情况。很容易想到的做法是在ListView中嵌套使用GridView,并且很多的人也在这样做。网上搜索ListView中嵌套使用GridView基本很大的一部分都会这样做。



首先看看这样怎么做,在ListView中嵌套GridView,需要的是将GridView的高度计算出来,不然GridView就可以滑动了。网上的做法,是自定义一个MyGridView(继承GridView),然后实现onMeasure()方法,计算出它的实际高度。(网上大神的源代码)

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
getLayoutParams().height = getMeasuredHeight();
}
然后将 MyGridView作为ListView的item的内容就行了,ListView的Adapter的实现还是以前的方式。(本来是用郭霖大神的CSDN上面的图片的拼成了一个Json串,然后用Universal-Image-Loader来下载展示图片,但是他的图片都是正方形的,还需要处理成长方形,就放弃了。直接使用了一张默认图,然后填了一些网易新闻的信息)最后的完成以后的效果是这样的。不知道你有没有发现一点异常,是的,有些item的第一张图片的显示有点问题。



看看stackoverflow中大神的回答。Grid of images inside ScrollView 



也就是说如果当GridView回收的比较频繁的时候,是不适合使用这样自定义GridView的方式的。那么是ListView中不能使用‘GridView’的了吗?但是,他的意思是自定义一个布局来显示。

也就是可以继承LinearLayout来实现,每行两个或者三个GridView的item,知道共有多少个,然后就可以自定义一个布局来实现。在这个布局中需要实现的是计算出它有多少行多少列。好吧,把数据的填充也写在这里面,但是,是的,但是,如何对GridView进行复用?Adapter中有这样的两个方法,getViewTypeCount()和getItemViewType(),可以知道ListView中是可以用多种不同类型的item,也就是说我如果有第一张图中的GridView
1和GridView 2中两种类型的话,在ListView滚动的过程中还是会复用的。在自定义这个布局的时候也需要基于这样的考虑,在实现布局和填充布局是分开的时候,也是需要考虑到复用,所以可以通过setTag()个getTag()的方式,在实现布局的时候每次都会通过setTag()的方式,在填充的时候则是每次都通过getTag()的方式。

public class MyGridView extends LinearLayout {

private final static String TYPE_HORIZONTAL = "horizontal";

private final static String TYPE_VERTICAL = "vertical";
/*
* 横图时显示2个
* */
private final static int NUM_HORIZONTAL = 2;

/*
* 竖图时显示3个
* */
private final static int NUM_VERTICAL = 3;

/*
* 自定义的类型,决定是2个还是3个
* */
private String mType;
/*
* 含有的列数
* */
private int mNumColumns = 0;

private Context mContext;
/*
*  该控件中的数据信息
* */
private ItemListView mData;

public MyGridView(Context context)
{
super(context);
}

public MyGridView(Context context, String type)
{
this(context);
this.mContext = context;
this.mType = type;
// 横着的时候是每行2个
if(TYPE_HORIZONTAL.equals(type))
{
mNumColumns = NUM_HORIZONTAL;
}
else if(TYPE_VERTICAL.equals(type))
{
// 竖着的时候则是每行3个
mNumColumns = NUM_VERTICAL;
}
// 方向是竖直的
this.setOrientation(VERTICAL);
}

/*
* 每一个MyGridView包含的布局
* */
public void addView()
{
addTitle();
addGridView();;
}

/*
* 布局的标题
* */
public void addTitle()
{
TitleLayoutHolder titleHolder = new TitleLayoutHolder();
View titleLayout = LayoutInflater.from(mContext).inflate(R.layout.mygridview_title, null);
titleHolder.layoutTitle = (TextView) titleLayout.findViewById(R.id.mygridview_view_title);
titleLayout.setTag(titleHolder);
this.addView(titleLayout); // 布局完成以后设置tag,方便填充数据
}

/*
* 布局的GridView部分
* */
public void addGridView()
{
if(mData == null)
{
return ;
}

// 根据屏幕的宽和每行的个数来计算宽度
int width = ((Activity)mContext).getWindowManager().getDefaultDisplay().getWidth();

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1);
int rowSpacing  = mContext.getResources().getDimensionPixelSize(R.dimen.image_spacing);

int size = mData.getList().size();
int numRow = size / mNumColumns + ( size % mNumColumns == 0 ? 0 : 1 );
// 遍历行
for(int i = 0;i < numRow; i++)
{
LinearLayout linearLayout = new LinearLayout(mContext); //每一行都是一个横向的LinearLayout
linearLayout.setOrientation(HORIZONTAL);

linearLayout.setPadding(rowSpacing, 0, rowSpacing , 0);
// 遍历列
for(int j = 0;j < mNumColumns && i * mNumColumns + j < size; j++)
{
View view = LayoutInflater.from(mContext).inflate(R.layout.mygridview_view, null);
view.setPadding(rowSpacing, rowSpacing, rowSpacing, rowSpacing);

ViewHolder holder = new ViewHolder();
holder.imageView = (ImageView) view.findViewById(R.id.mygridview_imageview);
// 计算出ImageView的高和宽
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.imageView.getLayoutParams();
int mImageHeight = 0;
int mImageWidth = 0;

if(mImageWidth == 0)
{
mImageWidth = width / mNumColumns;
}
// 分横竖屏计算出Image的高
if(TYPE_HORIZONTAL.equals(mType))
{
mImageHeight = mImageWidth * 9 / 16;
}
else if(TYPE_VERTICAL.equals(mType))
{
mImageHeight = mImageWidth * 4 / 3;
}
layoutParams.width = mImageWidth;
layoutParams.height = mImageHeight;

holder.overLap = (TextView) view.findViewById(R.id.overlap);
holder.title = (TextView) view.findViewById(R.id.title);

view.setTag(holder);
if (i == mImageWidth - 1)
{
linearLayout.addView(view, j);
}
else
{
linearLayout.addView(view, params);
}
}
this.addView(linearLayout);
}
}
/*
* 初始化数据,包括初始化布局
* */
public void setData(ItemListView data)
{
this.mData = data;
addView();

fillData(mData);
}

/*
* 将信息填充在MyGridView中
* */
public void fillData(ItemListView data)
{
if(data == null)
{
return;
}

this.mData = data;
// 得到含有的所有子项的信息
int childCount = getChildCount();

// 填充标题
TitleLayoutHolder titleLayoutHolder  = (TitleLayoutHolder) this.getChildAt(0).getTag();
titleLayoutHolder.layoutTitle.setText(data.getTitle());
// 填充view信息,从第1个到最后一个(是分行来加载的,就是填充View的每一行)
for( int i = 1; i < childCount; i ++ )
{
// 得到每一行的信息,包含多少个Item
ViewGroup linear = (ViewGroup) this.getChildAt(i);
int itemCount = linear.getChildCount();

// 每一行的起始的位置
int firstDataIndex = (i-1) * mNumColumns;

// 遍历每一行的信息,显示所有的item
for( int j = 0; j < itemCount; j ++)
{
// 所有信息包含的个数
int dataIndex = mData.getList().size();
if(firstDataIndex >= dataIndex)  //如果当前的下标已经大于了数据的长度,就退出
{
break;
}
// 得到本行的数据的信息
ItemListView.ItemGridView itemData = mData.getList().get(firstDataIndex);

ViewHolder holder = (ViewHolder) linear.getChildAt(j).getTag();

holder.overLap.setText(itemData.getOverlap());
holder.title.setText(itemData.getTitle());
holder.imageView.setBackgroundResource(R.mipmap.empty_photo);

firstDataIndex ++;
}
}
}

public  class TitleLayoutHolder
{
public TextView layoutTitle;
}

public class ViewHolder
{
public ImageView imageView;
public TextView overLap;
public TextView title;
}
}

在ListView对应的Adapter中,根据前面的需求,可以根据传过来的type以及包含的数量来决定一种类型。所以,Adapter可以这么写。

public class ItemListViewAdapter extends BaseAdapter {

// 原始数据
private List<ItemListView> list;
// 加工以后的数据,知道是什么类型的
private List<DataHolder> dataList;
private Context mContext;
private LayoutInflater mInflater;
// item的种类,可以根据Type字段和数量来做
private int mTypeCount = 0;

public ItemListViewAdapter(List<ItemListView> list, Context context)
{
this.list = list;
this.mContext = context;
mInflater = LayoutInflater.from(context);
// 在初始化的时候就需要计算出有多少种类
mTypeCount = countType();
}

@Override
public int getCount() {
return list==null ? 0 : list.size();
}

@Override
public Object getItem(int position) {
return list==null? null:list.get(position);
}

/*
* 根据list得到有多少种不同的类型
* */
private int countType()
{
if(list == null)
{
return 0;
}
// 默认的类型
int typeNum = 0;
// 总共含有的项
int size = list.size();
dataList = new ArrayList<DataHolder>();

boolean flag = false;
for (int i = 0;i < size;i ++)
{
flag = false;
DataHolder dataHolder = new DataHolder();
dataHolder.data = list.get(i);
for (int j = 0;j < i;j ++)
{
if(isSameType(dataHolder.data, dataList.get(j).data))
{
dataHolder.type = dataList.get(j).type;
flag = true;
break;
}
}
if (!flag)
{
dataHolder.type = typeNum++;
}
dataList.add(dataHolder);
}
return typeNum;
}
/*
* 判断src和dst是否相同的类型
* 类型相同并且含有的子项数量相同才相同
* */
private boolean isSameType(ItemListView src, ItemListView dst)
{
if(src == null || dst == null)
{
return false;
}
if(src.getType().equals(dst.getType()))
{
if(src.getList().size() == dst.getList().size())
{
return true;
}
}
return false;
}

/*
* 得到某一个position对应的类型
* */
@Override
public int getItemViewType(int position) {
return dataList == null ? 0 : dataList.get(position).type;
}

/*
* 计算出总体的类型
* */
@Override
public int getViewTypeCount() {
return mTypeCount > 0 ? mTypeCount : 1;
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
String type = list.get(position).getType();
MyGridView myGridView = null;
if(convertView == null)
{   // 如果为null的时候则需要初始化布局以及填充数据
myGridView = new MyGridView( mContext, type);
myGridView.setData(list.get(position));
}
else
{   // 如果不为null的时候只需要填充数据
myGridView = (MyGridView) convertView;
myGridView.fillData(dataList.get(position).data);
}

return myGridView;
}

/*
* 数据和数据的类型
* */
public class DataHolder
{
ItemListView data;
int type;
}
}
这样,应该就是完成了,最后,自己的数据。

public class Jsons {
public static String data = "{\"modules\":[{\"tid\":\"horizontal\",\"data\":{\"title\":\"头条\",\"dlist\":[{\"title\":\"访美花絮\",\"overlap\":\"习大大与美副总统开玩笑\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg\"},{\"title\":\"中国代表团\",\"overlap\":\"回应希拉里批评\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg\"},{\"title\":\"男子被刑拘\",\"overlap\":\"发布虚假信息\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg\"},{\"title\":\"山东小伙扶人被讹\",\"overlap\":\"车主愿作证\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg\"},{\"title\":\"东风日产\",\"overlap\":\"新蓝鸟预售正式启动\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg\"},{\"title\":\"范爷\",\"overlap\":\"李晨为范爷系鞋带\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"娱乐\",\"dlist\":[{\"title\":\"爸爸3\",\"overlap\":\"最后一站\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg\"},{\"title\":\"郭美美服刑\",\"overlap\":\"回原籍湖南\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg\"},{\"title\":\"孙红雷发黄磊结婚照\",\"overlap\":\"称好看\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg\"},{\"title\":\"张艺谋女儿做月饼\",\"overlap\":\"为妈妈庆生\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg\"}]}},{\"tid\":\"vertical\",\"data\":{\"title\":\"热点\",\"dlist\":[{\"title\":\"张嘉倪游走米兰街头\",\"overlap\":\"百变魅力令人心动\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg\"},{\"title\":\"上海最险匝道\",\"overlap\":\"明天通行\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg\"},{\"title\":\"南京虐童案\",\"overlap\":\"重新鉴定伤情\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg\"},{\"title\":\"装修后悔药\",\"overlap\":\"十大装修补救\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg\"},{\"title\":\"女神也风流\",\"overlap\":\"与男友亲昵\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg\"},{\"title\":\"十女配一夫\",\"overlap\":\"拉脱维亚\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg\"},{\"title\":\"世界新七大奇观\",\"overlap\":\"中国一处上榜\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg\"},{\"title\":\"中国最美的村庄\",\"overlap\":\"太美了\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg\"},{\"title\":\"华为Nexus 6p\",\"overlap\":\"细节大抄底\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg\"}]}},{\"tid\":\"vertical\",\"data\":{\"title\":\"体育\",\"dlist\":[{\"title\":\"亚锦赛\",\"overlap\":\"伊朗负菲律宾\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg\"},{\"title\":\"小贝辣妹关系紧张\",\"overlap\":\"互爆粗口\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg\"},{\"title\":\"恒大发亚冠最新海报\",\"overlap\":\"破五关\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg\"},{\"title\":\"哈达迪双手暴扣\",\"overlap\":\"犯满离场\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg\"},{\"title\":\"梅西微笑抵训练场\",\"overlap\":\"苏神成司机\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg\"},{\"title\":\"C罗被高估\",\"overlap\":\"远逊梅西\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"财经\",\"dlist\":[{\"title\":\"中国柴油排放造假\",\"overlap\":\"污染非常严重\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg\"},{\"title\":\"小米涉嫌虚假广告\",\"overlap\":\"被立案调查\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg\"},{\"title\":\"26位国企董事长\",\"overlap\":\"超期服役\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg\"},{\"title\":\"超级稻\",\"overlap\":\"被质疑\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg\"},{\"title\":\"一号店回应员工离职\",\"overlap\":\"正常流动\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg\"},{\"title\":\"人人网私有化\",\"overlap\":\"报价太低造质疑\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg\"},{\"title\":\"辽宁食药监局\",\"overlap\":\"辉山产品合格\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg\"},{\"title\":\"地下钱庄洗钱\",\"overlap\":\"公司账户全匿名\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"科技\",\"dlist\":[{\"title\":\"iphone 6s税额\",\"overlap\":\"够买一部红米\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg\"},{\"title\":\"无人机\",\"overlap\":\"在英国如何使用\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"图片\",\"dlist\":[{\"title\":\"大师创作\",\"overlap\":\"香港首条水墨阶梯\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg\"},{\"title\":\"游客三亚赏月\",\"overlap\":\"留下29吨垃圾\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg\"},{\"title\":\"长沙抬恐龙比赛\",\"overlap\":\"美女战肌肉男\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg\"},{\"title\":\"重庆600平米巨型国旗升旗\",\"overlap\":\"迎国庆\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"跟贴\",\"dlist\":[{\"title\":\"下次2033年\",\"overlap\":\"嫦娥大姨妈也嫌月球路远\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg\"},{\"title\":\"叶良辰\",\"overlap\":\"赵日天不服\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg\"},{\"title\":\"网购悲剧\",\"overlap\":\"财富很快就没了\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg\"},{\"title\":\"放屁污染\",\"overlap\":\"专家称放屁影响pm2.5\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg\"},{\"title\":\"瞎子掰玉米\",\"overlap\":\"掰一穗,丢一穗\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg\"},{\"title\":\"中秋寄思\",\"overlap\":\"举头望明月\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg\"}]}},{\"tid\":\"horizontal\",\"data\":{\"title\":\"直播\",\"dlist\":[{\"title\":\"马庸做客直播室\",\"overlap\":\"9月29日\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg\"},{\"title\":\"台湾金钟奖\",\"overlap\":\"第50届\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg\"},{\"title\":\"中超-鲁能VS上港\",\"overlap\":\"争冠焦点战\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg\"},{\"title\":\"网易时尚\",\"overlap\":\"Etro秀场直播\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg\"}]}},{\"tid\":\"vertical\",\"data\":{\"title\":\"轻松时刻\",\"dlist\":[{\"title\":\"小编漫话\",\"overlap\":\"新时代发财路\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg\"},{\"title\":\"新闻七点整\",\"overlap\":\"吃别人剩下的\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg\"},{\"title\":\"深夜畅聊\",\"overlap\":\"个人隐私\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg\"},{\"title\":\"暴走大事件\",\"overlap\":\"第四季\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg\"},{\"title\":\"一见你就笑\",\"overlap\":\"大学生了吗?\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg\"},{\"title\":\"轻松一刻语音版\",\"overlap\":\"低调求婚\",\"img\":\"http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg\"}]}}]}";
}

最后的效果图是这样的,还不错,滑动的时候也不会出现问题。



就不给源码了,哈哈。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息