欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详解Android使GridView横向水平滚动的实现方式

程序员文章站 2023-11-29 16:51:34
android为我们提供了竖直方向的滚动控件gridview,但如果我们想让它水平滚动起来,就需要自己实现了。 以下使用的测试数据datas集合都为list

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);
  }

一、单行横向显示

详解Android使GridView横向水平滚动的实现方式

实现思路

  1. 在代码中动态设置gridview的numcolumns,使其等于gridview要显示的数据集合大小。
  2. 动态设置item项宽度,结合数据集合大小来设置gridview的总宽度。
  3. 使用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适配器就能实现单行横向滚动了,适配器使用常规的实现方式就行,这里就不贴了

二、多行横向分页显示

详解Android使GridView横向水平滚动的实现方式

实现思路

  1. 使用viewpager实现左右翻页效果。
  2. 根据数据集合大小,计算出要显示的页数,并生成相应数量的gridview。
  3. 在gridview的adapter适配器中,动态分配gridview需要显示的数据集合。
  4. 使用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来实现此类需求。

希望对大家的学习有所帮助,也希望大家多多支持。