博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中ListView嵌套GridView的简单消息流UI(解决宽高问题)
阅读量:5278 次
发布时间:2019-06-14

本文共 4302 字,大约阅读时间需要 14 分钟。

最近搞一个项目,需要用到类似于新浪微博的消息流,即每一项有文字、有九宫格图片,因此这就涉及到ListView或者ScrollView嵌套GridView的问题。其中GridView的高度问题在网上都很容易找到答案,即覆写onMeasure方法,然后设置高度的MeasureSpec。但是宽度问题确实没有什么资料,这里所说的宽度问题是比如GridView的列数为3,那么即使只有一张图片,gridview的宽度也是match_parent的,导致用户点击在图片范围外但是在gridview范围内时ListView的点击事件不能捕获。

如图 :

width=200

出现的问题截图如上,当只有一个图标时GridView的宽度(灰色区域)也是match_parent的,这个时候点击gridview区域是ListView是不能响应的,但是如果GridView的背景色与ListView的背景一致,用户是看不到GridView的宽度,当用户点击图片以外的区域,可能的操作就是进入到该条消息的详情页,但是由于此时GridView是match_parent的,所以ListView根本不会获取到点击事件,这样的体验很不好。我们需要的效果是这样的 :

width=200

即GridView的大小刚好能够包含图片的大小,这样当GridView的背景色为默认时,用户点击图片以外的区域就是点击了ListView的Item。

我们看看如何解决这个问题吧,首先布局方面就不讲了,主要还是讲讲GridView的宽高问题吧。解决GridView的高度问题,需要覆写GridView的onMeasure方法,代码如下 :

public class MGridView extends GridView {     public boolean hasScrollBar = true;     /**     * @param context     */    public MGridView(Context context) {        this(context, null);    }     public MGridView(Context context, AttributeSet attrs) {        super(context, attrs, 0);    }     public MGridView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }     @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         int expandSpec = heightMeasureSpec;        if (hasScrollBar) {            expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,                    MeasureSpec.AT_MOST);            super.onMeasure(widthMeasureSpec, expandSpec);// 注意这里,这里的意思是直接测量出GridView的高度        } else {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);        }    } }

在onMeasure方法中,因为hasScrollBase为true, 我们会注意到代码中有注释的分支。这里实际上就是在onMeasure的时候计算出GridView的高度,而不是只计算其中几个View的高度。如果没有这一步,那么GridView的高度将显示不全。将GridView的高度计算出来,这样就不需要上下滑动来显示其它的item了,因为问题所在就是GridView嵌套在了ScrollView或者包含ScrollView的中,从而引发的冲突。

下面解决宽度的问题,思路就是在ListView的getView方法中手动计算每个GridView的图片个数,如果图片个数小于GridView每行的列数,则手动计算每个child view所需的宽度,然后GridView的宽度 = child个数 * 每个child view的宽度。为了避免重复计算,我们会缓存计算结果。计算代码如下 :

/** * @author mrsimple */public final class GridViewUtils {    /**     * 存储宽度     */    static SparseIntArray mGvWidth = new SparseIntArray();     /**     * 计算GridView的高度     *      * @param gridView 要计算的GridView     */    public static void updateGridViewLayoutParams(MGridView gridView, int maxColumn) {        int childs = gridView.getAdapter().getCount();         if (childs > 0) {            int columns = childs < maxColumn ? childs % maxColumn : maxColumn;            gridView.setNumColumns(columns);            int width = 0;            int cacheWidth = mGvWidth.get(columns);            if (cacheWidth != 0) {                width = cacheWidth;            } else { // 计算gridview每行的宽度, 如果item小于3则计算所有item的宽度;                     // 否则只计算3个child宽度,因此一行最多3个child。 (这里我们以3为例)                int rowCounts = childs < maxColumn ? childs : maxColumn;                for (int i = 0; i < rowCounts; i++) {                    View childView = gridView.getAdapter().getView(i, null, gridView);                    childView.measure(0, 0);                    width += childView.getMeasuredWidth();                }            }             ViewGroup.LayoutParams params = gridView.getLayoutParams();            params.width = width;            gridView.setLayoutParams(params);            if (mGvWidth.get(columns) == 0) {                mGvWidth.append(columns, width);            }        }    }

ListView的getView方法如下 :

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {    ViewHolder viewHolder = null;     if (convertView == null) {        convertView = mInflater.inflate(R.layout.listview_item, parent, false);        viewHolder = new ViewHolder();        viewHolder.mGridView = (MGridView) convertView.findViewById(R.id.my_gridview);        viewHolder.mTextView = (TextView) convertView.findViewById(R.id.my_tv);        convertView.setTag(viewHolder);    } else {        viewHolder = (ViewHolder) convertView.getTag();    }     final ListViewItem item = getItem(position);    // 设置GridView的Adapter    viewHolder.mGridView.setAdapter(new GridViewAdapter(mContext, item.mImages));    // 计算GridView宽度, 设置默认为numColumns为3.    GridViewUtils.updateGridViewLayoutParams(viewHolder.mGridView, 3);    viewHolder.mTextView.setText(item.mText);    return convertView;}

这样,我们就解决了消息流的宽高问题。

转载于:https://www.cnblogs.com/zhujiabin/p/5533171.html

你可能感兴趣的文章
【HTML】网页中如何让DIV在网页滚动到特定位置时出现
查看>>
文件序列化
查看>>
jQuery之end()和pushStack()
查看>>
Bootstrap--响应式导航条布局
查看>>
Learning Python 009 dict(字典)和 set
查看>>
JavaScript中随着鼠标拖拽而移动的块
查看>>
HDU 1021 一道水题
查看>>
The operation couldn’t be completed. (LaunchServicesError error 0.)
查看>>
php每天一题:strlen()与mb_strlen()的作用分别是什么
查看>>
工作中收集JSCRIPT代码之(下拉框篇)
查看>>
《转载》POI导出excel日期格式
查看>>
code异常处理
查看>>
git - 搭建最简单的git server
查看>>
会话控制
查看>>
推荐一款UI设计软件Balsamiq Mockups
查看>>
Linux crontab 命令格式与详细例子
查看>>
百度地图Api进阶教程-地图鼠标左右键操作实例和鼠标样式6.html
查看>>
游标使用
查看>>
LLBL Gen Pro 设计器使用指南
查看>>
SetCapture() & ReleaseCapture() 捕获窗口外的【松开左键事件】: WM_LBUTTONUP
查看>>