Android之GridView控制显示多少行以及遇到的怪事
前段时间接到一个需求,要求GridView超过两行只显示两行多余的不显示。但是GridView没有设置多少行的api,只有设置多少列的方法,到处查找资料都类似的case,stakeoverfrow上面也没什么有价值的答案,不过在百度知道竟然看到了一个思路。
知道:http://zhidao.baidu.com/link?url=f-F4MnuKApNqgTzcW0r7nUDljHch3v-iGV7LspkMFW97ftxgh0JJSwhdRYkipzK4zdyBoWfJZ9ZakJoAnBppKq
第一个方案:说定死列数,算出总数,只有显然不科学,因为我的gridview列数十需要autofit的,随手机屏幕多宽就相应显示多少列。
gridview的xml属性 android:numColumns="6"在adapter里重写@Override public int getCount() { return 12; }这样应该行吧
第二个方案:限定gridview高度,因为项目时间很紧所以脑子里也曾蹦出这个想法,试着写死一个固定高度,但事实上这高度是不起作用的,因为它是根据adapte的条目来计算的。
第三个方案:其实就是第一个方案改良版,虽然是很朴素的思路但是可以改活。在探索过程中发现gridview在高版api中有一个获取列数的方法,如果知道到列数那就好办了,列数*2就得到了要显示两行的count,这样既满足列数自适应又很优雅的控制要显示的区域。
=====================================================================
于是代码可以写下去了:
int numberOfColumns = mGridView.getNumColumns();
if (numberOfColumns > 0) {//adapter item 数据已填充
int countOf2Row = numberOfColumns * 2;
for (int i = count2Row - 1; i < couponList.size(); i++)
mDataSources.remove(i);//多出2列的数据cut掉
if (mAdapter != null) mAdapter.notifyDataSetChanged();
}
这个if死活没进去啊,打印出来看到获取到的NumColumn是-1,然后看到方法doc:
Get the number of columns in the grid.
* Returns {@link #AUTO_FIT} if the Grid has never been laid out.
我明明是在adapte.notifyDatasetChanged()方法之后去获取的啊,怎么还是拿不到,查阅了一些资料之后就监听gridview布局变化,在listener里面果然能获取到了。
刚才说到getNumColumns()是高版方法,API11以上才有,所以还得back compat。这个只要网上搜索一下一大把,我也是摘抄了一段。
/**
* 获取列数的兼容方法.
* @return
*/
public int getNumColumnsCompat() {
if (Build.VERSION.SDK_INT >= 11) {
return getNumColumnsCompat11();
} else {
int columns = 0;
int children = getChildCount();
if (children > 0) {
int width = getChildAt(0).getMeasuredWidth();
if (width > 0) {
columns = getWidth() / width;
}
}
return columns > 0 ? columns : AUTO_FIT;
}
} @TargetApi(Build.VERSION_CODES.HONEYCOMB)
private int getNumColumnsCompat11(){
return getNumColumns();
}
那最后代码变成这样了:
mGridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int numberOfColumns = ((MyGridView) mGridView).getNumColumnsCompat();
if (numberOfColumns > 0) {//adapte item 数据已填充
int count2Row = numberOfColumns * 2;
for (int i = count2Row - 1; i < couponList.size(); i++)
list.remove(i);//多出2列的数据cut掉
if (mAdapter != null) mAdapter.notifyDataSetChanged();
ApiVersionCompat.removeOnGlobalLayoutListener(mGridView.getViewTreeObserver(), this);
}
}
});
注意在onGlobalLayout处理好移除数据的逻辑之后需要移除监听器哦,移除监听也有一个版本差异,代码送上:
public static void removeOnGlobalLayoutListener(ViewTreeObserver observer, ViewTreeObserver.OnGlobalLayoutListener victim) {
if (Build.VERSION.SDK_INT >= 16) {
observer.removeOnGlobalLayoutListener(victim);
} else {
observer.removeGlobalOnLayoutListener(victim);
}
}
本以为就perfect了事了,feature也实现了,资源也节约了(因GroblaLayoutListener会多次触发,所以一定要做好限制,用完就释放掉不要让代码重复执行了)。代码交上去,apk发给测试测了之后bug就丢过来了,测试出来说还是有不止两行的grid出现啊,我心里怎么也不相信啊,怎么可能我明明自测过的。

当我重新打开app,发现确实有超出2行多出一个Item掉在第三行,后来就怀疑是不是cut数据没控制好,代码明明是for (int i = count2Row - 1; i < list.size(); i++)这样循环啊。每次都多出一个,难道i<=list.size(),我也曾很多次怀疑过怎么可能会list.remove(list.size()),不可能不可能不可能啊,这样绝对会数组越界啊,难不成是i初始还要count2Row-2,试过之后还是如此多一个(因为总数是有9个,从第六个开始剪掉2个也还是有一个)。
log出size让我惊讶了,size竟然是6,但接口出来明明是9啊。然后就猛然一醒,加载数据和触发布局改变事件应该是异步的,也就是说当我在布局改变事件中获取到列数>0时,并不一定数据全部加载完,而这时我已经移除监听了。当加载到第1行数据的时候就可以获取到列数了,恰好此时我移除了其中几个(如果第一次获取到的size大于2列之和小于最终size),但当处理完这块逻辑的同时数据其实还是在加载的,虽然都是微乎其微的瞬间,但也有先来后到的顺序,所以移除掉一部分后面又添加了一部分,结果就出现了超过两行的情况。
mGridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int numberOfColumns = ((MyGridView) mGridView).getNumColumnsCompat();//有可能每次会有变动
if (numberOfColumns > 0) {//adapter item 数据已填充
int countOf2Row = numberOfColumns * 2;
if (list.size() > countOf2Row) {
//超出2行(第三行开始)的数据cut掉
for (int i = countOf2Row; i < list.size(); i++) {
mAdapter.remove(i);
}
if (mAdapter != null) mAdapter.notifyDataSetChanged();
} else {
//每次检测到数据集合大小<=countOf2Row的时候就可以移除监听了
ApiVersionCompat.removeOnGlobalLayoutListener(mGridView.getViewTreeObserver(), this);
}
}
}
});
好了,代码写好了,自测一下也都OK了,多测几个不一样的数据也正常了。可该死的,不小心按到了home键,当打开recent列表点回app的时候发现大事不好,又整整齐齐得出现三行满满的。

原来这个界面是会在onResure刷新数据的,View都还是那些View,但是数据会重新添加,第一次完美显示2行,但数据一刷新,就会先clear掉数据源重新添加数据,而此时的GlobalLayoutListener已经移除了无法监听处理多出2行的逻辑了,所以如上图所示,完完整整的出现了3行数据。因为我addOnGlobalLayoutListener是在initViews时候去注册的,当数据加载完毕就移除监听,原来以为很完美没想到会有这种情况发生。那知道了问题在哪就好对症下药了,直接把添加监听的方法放在拿到数据后执行就好了,每次到数据就监听处理,处理完了就移除监听,下次数据来了依然也可以依次执行。
代码就不贴了,说的很清楚了,此处应扫二维码关注公众号了!

Android之GridView控制显示多少行以及遇到的怪事的更多相关文章
- Android成长日记-使用GridView显示多行数据
本节将实现以下效果 Ps:看起来很不错的样子吧,而且很像九宫格/se ----------------------------------------------------------------- ...
- Android 使用GridView以表格的形式显示多张图片
GridView用于在界面上按行.列分布的方式来显示多个组件(而ListView只是以按行的方式) 课程目标 学会使用GridView制作二维布局界面(行.列分布) 数据源(集合) --> 适配 ...
- Android Studio gridview 控件使用自定义Adapter, 九宫格items自适应全屏显示
先看效果图,类似于支付宝首页的效果.由于九宫格显示的帖子网上已经很多,但是像这样九宫格全屏显示的例子还不是太多.本实例的需求是九宫格全屏显示,每个子view的高度是根据全屏高度三等分之后自适应高度,每 ...
- Android studio 显示代码行号 设置
首先我们打开我们的Android Studio. 这时会弹出setting页面,我们选择show line numbers然后点击确定按钮. 此时我们就可以看到代码左侧显示出行号了 我们可 ...
- Android GridView 一行显示数据(包括图片和文本),解决的办法是计算数据占该行的宽度是多少
最近在做图片的浏览功能,开始是使用Gallery做,但是,达不到我想要的效果,关于使用Gallery显示缩略图的缺点和优点,不在详述了.以下是一个完整的Demo代码,注意我的模拟器是640*960. ...
- 使用css控制文字显示几行并且剩余部分隐藏(移动端和PC端同样适用)
前言 有些需求需要我们控制一段文本最多显示几行,就像逛淘宝京东的评价楼层一样,有时可能还需要隐藏剩余部分,这样的需求我们怎么来解决呢? 解决办法 我们完全可以使用css来解决这一需求 1. 解决文本显 ...
- 纯css控制文字2行显示多余部分隐藏
在编写页面的时候,经常遇到一些地方的文字显示1行,多余的文字隐藏,这样显示1行的很好控制: css代码如下: white-space: nowrap; overflow: hidden; text-o ...
- Android ScrollView嵌套GridView导致GridView只显示一行item
Android ScrollView嵌套GridView导致GridView只显示一行item Android ScrollView在嵌套GridView时候,会导致一个问题发生:GridView只显 ...
- Android——GridView(显示文字)
activity_test9的layout文件: <?xml version="1.0" encoding="utf-8"?> <Linear ...
随机推荐
- HTTP权威指南阅读笔记二:URL与资源
URL中的限制字符: 在URL中,有几个字符被保留起来,有着特殊的含义.有些字符不在定义的US-ASCII可打印字符集中.还有些字符会与某些因特网网关和协议产生混淆,因此不赞成使用. 下面这些字符是U ...
- [ACM_图论] Fire Net (ZOJ 1002 带障碍棋盘布炮,互不攻击最大数量)
Suppose that we have a square city with straight streets. A map of a city is a square board with n ...
- We are doomed, and RPC does not help
第一种死法:Big ball of Mud 架构里最常用的反面案例是 big ball of mud.很大程度上可以说打格子,把复杂的系统拆解成小格子是架构师最重要的工作.这个小格子有很多种名字,比如 ...
- paip.c3p0 数据库连接池 NullPointerException 的解决...
paip.c3p0 数据库连接池 NullPointerException 的解决... 程序ide里面运行正常..外面bat运行错误.. 作者Attilax 艾龙, EMAIL:14665198 ...
- iOS图片加载速度极限优化—FastImageCache解析
FastImageCache是Path团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动 优化点 iOS从磁盘加载一张图片,使用UIImageVIew显示在屏幕上,需要经过以下步 ...
- 跑PIN码破解无线网络WIFI密码的原理分析(转)
你们家用的无线路由器安全吗?有人蹭网吗?无线路由器的漏洞在哪里?这么避免蹭网? 想要了解这些,必须要了解加密以及破解原理. 工具/原料 电脑 足够多足够好的wifi信号源 usb无线网卡(非必需) 一 ...
- NAS服务器局域网内IPad、手机、电视盒子等联网播放
为把各个移动硬盘和不同电脑的数据进行统一管理,入手了一台希捷 Seagate Business 无内置硬盘 商业级 2盘位 云存储网路存储,经过卖家指点和不断摸索,终于能用了,主要步骤如下: 1. 系 ...
- zz A list of open source C++ libraries
A list of open source C++ libraries < cpp | links http://en.cppreference.com/w/cpp/links/libs Th ...
- 解决Visual Studio 2010/2012的RC4011 warnings
如果在vc10/11工程的rc文件中有以下任意一行代码: #include <winuser.h> #include <richedit.h> 那么vc将会给出一对警告: C: ...
- JavaScript 中数组实用浅析
本文适用于HTML.ASP 中的 JavaScript 脚本代码.代码以 HTML 中的 JS 为例,如果在 ASP 中,请将 document.write 改为 Response.Write 即可. ...