详解Android使GridView横向水平滚动的实现方式
android为我们提供了竖直方向的滚动控件gridview,但如果我们想让它水平滚动起来,就需要自己实现了。
以下使用的测试数据datas集合都为list<resolveinfo>类型,用来存储手机中的所有app
public static list<resolveinfo> getappdata(context context) { packagemanager packagemanager = context.getpackagemanager(); intent mainintent = new intent(intent.action_main, null); mainintent.addcategory(intent.category_launcher); return packagemanager.queryintentactivities(mainintent, 0); }
一、单行横向显示
实现思路
- 在代码中动态设置gridview的numcolumns,使其等于gridview要显示的数据集合大小。
- 动态设置item项宽度,结合数据集合大小来设置gridview的总宽度。
- 使用horizontalscrollview包裹gridview
具体实现
关键代码
/** * 将gridview改成单行横向布局 */ private void changegridview() { // item宽度 int itemwidth = densityutil.dip2px(this, 100); // item之间的间隔 int itempaddingh = densityutil.dip2px(this, 1); int size = datas.size(); // 计算gridview宽度 int gridviewwidth = size * (itemwidth + itempaddingh); linearlayout.layoutparams params = new linearlayout.layoutparams( gridviewwidth, linearlayout.layoutparams.match_parent); mcontentgv.setlayoutparams(params); mcontentgv.setcolumnwidth(itemwidth); mcontentgv.sethorizontalspacing(itempaddingh); mcontentgv.setstretchmode(gridview.no_stretch); mcontentgv.setnumcolumns(size); }
这里用到的dip2px方法是根据手机的分辨率从 dp 的单位 转成为 px(像素)
/** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) * @param context 上下文 * @param dpvalue dp值 * @return px值 */ public static int dip2px(context context, float dpvalue) { final float scale = context.getresources().getdisplaymetrics().density; return (int) (dpvalue * scale + 0.5f); }
在布局文件中,使用horizontalscrollview包裹gridview
<horizontalscrollview android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none"> <linearlayout android:layout_width="match_parent" android:layout_height="match_parent"> <gridview android:id="@+id/gv_horizontal_gridview_line" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none"/> </linearlayout> </horizontalscrollview>
通过以上设置,再加上adapter适配器就能实现单行横向滚动了,适配器使用常规的实现方式就行,这里就不贴了
二、多行横向分页显示
实现思路
- 使用viewpager实现左右翻页效果。
- 根据数据集合大小,计算出要显示的页数,并生成相应数量的gridview。
- 在gridview的adapter适配器中,动态分配gridview需要显示的数据集合。
- 使用list保存多个gridview实例并传入viewpager适配器中,一页viewpager对应一个gridview实例。
具体实现
数据量很多时,需要进行分页,计算方式
需要页数 = 总数量 ÷ 每页显示数量
有些整除不了的,就需要使用math.ceil()函数,向上取整
关键代码
/** * 获取系统所有的应用程序,根据每页需要显示的item数量,生成相应数量的gridview页面 */ private void initviews(list<resolveinfo> datas) { int datasize = datas.size(); // (需要页数 = 总数量 ÷ 每页显示数量)向上取整数 int pagecount = (int) math.ceil(datasize / app_size); mgridviewlist = new arraylist<>(); for (int i = 0; i <= pagecount; i++) { gridview apppage = new gridview(this); apppage.setadapter(new horizontalgvadapter(this, datas, i)); apppage.setnumcolumns(4); apppage.setverticalspacing(1); apppage.sethorizontalspacing(1); apppage.sethorizontalscrollbarenabled(false); apppage.setverticalscrollbarenabled(false); mgridviewlist.add(apppage); } if(datasize % app_size == 0){ mgridviewlist.remove(mgridviewlist.size()-1); pagecount--; } mgvpageradapter = new horizontalgvpageradapter(mgridviewlist); viewpager.setadapter(mgvpageradapter); viewpager.addonpagechangelistener(new mypagechangelistener()); adddot(pagecount); }
当总数量 ÷ 每页显示数量刚好被整除时,会出现一页空白页的情况,这个时候需要去掉多出来的那一页
if(datasize % app_size == 0){ mgridviewlist.remove(mgridviewlist.size()-1); pagecount--; }
adapter在创建初期就要对显示的数据进行控制,因为这里每个gridview都有一个单独的adapter,所以需要对其显示的datas进行动态计算
通过传入构造方法的数据进行动态计算,可以得出数据开始加载的位置、结束加载的位置
horizontalgvadapter的构造方法:
/** * 所有应用数据 */ private list<resolveinfo> mappdatas = new arraylist<resolveinfo>(); public horizontalgvadapter(context context, list<resolveinfo> list, int page) { this.mcontext = context; // 开始加载的位置 int pagestart = page * horizontalgridviewact.app_size; // 结束加载的位置 int pageend = pagestart + horizontalgridviewact.app_size; while ((pagestart < list.size()) && (pagestart < pageend)) { mappdatas.add(list.get(pagestart)); pagestart++; } }
如果需要加小圆点的话,可以先在布局中用一个空linearlayout当小圆点的容器
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical"> <android.support.v4.view.viewpager android:id="@+id/vp_horizontal_gridview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_gravity="center" android:background="#c5c5c5" android:scaletype="fitxy"/> <!-- 底部小圆点 --> <linearlayout android:id="@+id/ll_dot_container" android:layout_width="match_parent" android:layout_height="50dp" android:background="#4b4b4b" android:layout_gravity="bottom" android:gravity="center" android:orientation="horizontal"/> </linearlayout>
然后在代码中用list<view>来保存创建的小圆点
// 放圆点的list private list<view> dotviewslist; /** * 创建指定数量的圆点 * @param dotnumber viewpager的数量 */ private void adddot(int dotnumber) { if (null == dotviewslist) { dotviewslist = new arraylist<view>(); } linearlayout dotlayout = (linearlayout) findviewbyid(r.id.ll_dot_container); for (int i = 0; i <= dotnumber; i++) { imageview dotview = new imageview(this); linearlayout.layoutparams params = new linearlayout.layoutparams( framelayout.layoutparams.wrap_content, framelayout.layoutparams.wrap_content); // 圆点与圆点之间的距离 params.leftmargin = 10; params.rightmargin = 10; // 圆点的大小 params.height = 15; params.width = 15; dotlayout.addview(dotview, params); dotviewslist.add(dotview); } // 设置圆点默认选中第一个 setdotshow(0); } 动态添加完小圆点后,就可以设置它们的选中状态了,这里只需要更改对应小圆点的图片显示就行 /** * 显示底部圆点导航 * @param position 选中哪个圆点 */ private void setdotshow(int position){ if (dotviewslist == null){ return; } for (int i = 0; i < dotviewslist.size(); i++) { if (i == position) { dotviewslist.get(position).setbackgroundresource(r.drawable.ic_dot_on); } else { dotviewslist.get(i).setbackgroundresource(r.drawable.ic_dot_off); } } }
三、总结
以上就是让gridview横向滚动的实现方式,其实我们完全可以不必这么麻烦,google在support-v7包中为我们提供了recyclerview控件,切换横向和竖直滚动只需要让布局管理器使用setorientation方法设置一下就好,非常便捷,如果项目允许,建议使用recyclerview来实现此类需求。
希望对大家的学习有所帮助,也希望大家多多支持。