最近搞一个项目,需要用到类似于新浪微博的消息流,即每一项有文字、有九宫格图片,因此这就涉及到ListView或者ScrollView嵌套GridView的问题。其中GridView的高度问题在网上都很容易找到答案,即覆写onMeasure方法,然后设置高度的MeasureSpec。但是宽度问题确实没有什么资料,这里所说的宽度问题是比如GridView的列数为3,那么即使只有一张图片,gridview的宽度也是match_parent的,导致用户点击在图片范围外但是在gridview范围内时ListView的点击事件不能捕获。
如图 :
出现的问题截图如上,当只有一个图标时GridView的宽度(灰色区域)也是match_parent的,这个时候点击gridview区域是ListView是不能响应的,但是如果GridView的背景色与ListView的背景一致,用户是看不到GridView的宽度,当用户点击图片以外的区域,可能的操作就是进入到该条消息的详情页,但是由于此时GridView是match_parent的,所以ListView根本不会获取到点击事件,这样的体验很不好。我们需要的效果是这样的 :
即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方法如下 :
@Override
public 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;
}
这样,我们就解决了消息流的宽高问题。
demo地址 :猛击这里~
分享到:
相关推荐
Android 中ScrollView嵌套GridView,ListView的实例 在Android开发中,经常有一些UI需要进行固定style的动态布局,然而由于现在的UI都喜欢把一个界面拉的很长,所以我们很多情况下需要使用ScrollView来嵌套列表控件...
[四次元]Android中实现Iphone样式的AlertDialog.zip [四次元]Android实现Windows风格的Dialog.zip [四次元]dlna库源代码包.zip [四次元]gridview分页效果.zip [四次元]HerilyAlertDialog完全自定义的Dialog.zip [四...
3.2 Android中的组件介绍 22 3.3 使用Android SDK帮助 23 3.3.1 Android SDK API文档 23 3.3.2 Android SDK开发指南 24 3.3.3 Android SDK samples 24 3.4 使用DDMS帮助调试程序 26 3.4.1 启动DDMS 26 3.4.2 ...
最近参与了开发一款旅行APP,其中包含实时聊天和...一拿到主流的UI需求,大致分析下,需要我ListView嵌套Gridview,而gridView的行数也和图片总数有关系,因此通过个数我们可以动态设置条目的宽高,而点击图片放大我
Android Swipe Layout可以轻松集成到ListView,GridView,ViewGroup等任何位置。它可以接收onOpen,onClose,onUpdate回调。 也可以通知隐藏的孩子他们显示了多少。 Android Swipe Layout允许您将滑动与UI组件集成在...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像。 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像 . 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。可以接收 onOpen、onClose、onUpdate 回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像这样。 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像 . 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像 . 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像 . 用法 步骤1 ...
可以轻松集成在任何地方,ListView、GridView、ViewGroup 等。 可以接收onOpen 、 onClose 、 onUpdate回调。 可以通知隐藏的孩子他们已经展示了多少。 可以互相嵌套。 可以处理复杂的情况,就像 . 用法 步骤1 ...
右边的listView再嵌套一个GridView即可。如下图所示。 所以,我们需要的数据结构也就确定了,应该是数组套数组,也就说护肤大分类下又有子分类商品,类似于这个样子: ok,数据和UI结构确定了,就可以编写代码了 ...