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

小圆点添加好后,需要根据ViewPager的页面位置设置圆点的选中状态,所以还需要添加一个监听器,监听ViewPager当前是第几个页面,然后根据这个页面的值来改变小圆点的选中位置

    /**
     * ViewPager的监听器 动态改变小圆点的选中位置
     */
    private class MyPageChangeListener implements ViewPager.OnPageChangeListener {

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageSelected(int pos) {
            setDotShow(pos);
        }

    }

三、总结

以上就是让GridView横向滚动的实现方式,其实我们完全可以不必这么麻烦,Google在support-v7包中为我们提供了RecyclerView控件,切换横向和竖直滚动只需要让布局管理器使用setOrientation方法设置一下就好,非常便捷,如果项目允许,建议使用RecyclerView来实现此类需求。

已标记关键词 清除标记
在网上看了好多DEMO效果都不是想要的然后发现了这个例子下面贴出来 package com.example.bmvod.myapplication; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public class MainActivity extends Activity { private LinearLayout linear01; private LinearLayout linear02; private List<Map<String, Object>> listView; private int next = 0; private ViewPager adViewPager; private AdPageAdapter adapter; private ImageView[] imageViews; private ImageView imageView; private AtomicInteger atomicInteger = new AtomicInteger(0); private boolean isContinue = true; private List<View> gridViewlist = new ArrayList<View>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { System.out.println("initView()"); linear01 = (LinearLayout) findViewById(R.id.view_pager_content); linear02 = (LinearLayout) findViewById(R.id.viewGroup); listView = new ArrayList<Map<String, Object>>(); //创建ViewPager adViewPager = new ViewPager(this); //获取屏幕像素相关信息 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //根据屏幕信息设置ViewPager广告容器的宽高 //adViewPager.setLayoutParams(new LayoutParams(dm.widthPixels, dm.heightPixels)); //将ViewPager容器设置到布局文件父容器中 linear01.addView(adViewPager); getView(); initCirclePoint(); adViewPager.setAdapter(adapter); adViewPager.addOnPageChangeListener(new AdPageChangeListener()); } /** * ViewPager 页面改变监听器 */ private final class AdPageChangeListener implements OnPageChangeListener { /** * 页面滚动状态发生改变的时候触发 */ @Override public void onPageScrollStateChanged(int arg0) { } /** * 页面滚动的时候触发 */ @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } /** * 页面选中的时候触发 */ @Override public void onPageSelected(int arg0) { //获取当前显示的页面是哪个页面 System.out.println("onPageSelected"); atomicInteger.getAndSet(arg0); //重新设置原点布局集合 for (int i = 0; i < imageViews.length; i++) { imageViews[arg0].setBackgroundResource(R.drawable.point_focused); if (arg0 != i) { imageViews[i].setBackgroundResource(R.drawable.point_unfocused); } } } } private void initCirclePoint() { System.out.println("initCirclePoint()"); imageViews = new ImageView[gridViewlist.size()]; //广告栏的小圆点图标 for (int i = 0; i < gridViewlist.size(); i++) { //创建一个ImageView, 并设置宽高. 将该对象放入到数组中 imageView = new ImageView(this); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT); layoutParams.setMargins(10, 0, 10, 0); imageView.setLayoutParams(layoutParams); imageViews[i] = imageView; //初始值, 默认第0个选中 if (i == 0) { imageViews[i].setBackgroundResource(R.drawable.point_focused); } else { imageViews[i].setBackgroundResource(R.drawable.point_unfocused); } //将小圆点放入到布局中 linear02.addView(imageViews[i]); } } private void getView() { int[] intView = {R.drawable.one, R.drawable.two, R.drawable.three, R.drawable.four, R.drawable.five, R.drawable.six, R.drawable.seven, R.drawable.eight, R.drawable.nine, R.drawable.ten , R.drawable.eleven, R.drawable.twelve, R.drawable.thirteen, R.drawable.fourteen, R.drawable.fifteen, R.drawable.sixteen, R.drawable.seventeen}; for (int i = 0; i < intView.length; i++) { Map<String, Object> mapView = new HashMap<String, Object>(); mapView.put("image", intView[i]); listView.add(mapView); } getGridView(); } private void getGridView() { boolean bool = true; while (bool) { int result = next + 9; if (listView.size() != 0 && result < listView.size()) { GridView gridView = new GridView(this); gridView.setNumColumns(5); gridView.setVerticalSpacing(30); gridView.setHorizontalSpacing(0); List<Map<String, Object>> gridlist = new ArrayList<Map<String, Object>>(); for (int i = next; i < result; i++) { gridlist.add(listView.get(i)); } MyAdapter myAdapter = new MyAdapter(gridlist); gridView.setAdapter(myAdapter); next = result; gridViewlist.add(gridView); } else if (result - listView.size() <= 9) { System.out.println("剩余多少" + (result - listView.size())); List<Map<String, Object>> gridlist = new ArrayList<Map<String, Object>>(); for (int i = next; i < listView.size(); i++) { gridlist.add(listView.get(i)); } GridView gridView = new GridView(this); gridView.setNumColumns(5); MyAdapter myAdapter = new MyAdapter(gridlist); gridView.setAdapter(myAdapter); next = listView.size() - 1; gridViewlist.add(gridView); bool = false; } else { bool = false; } } adapter = new AdPageAdapter(gridViewlist); } private final class AdPageAdapter extends PagerAdapter { private List<View> views = null; /** * 初始化数据源, 即View数组 */ public AdPageAdapter(List<View> views) { this.views = views; } /** * 从ViewPager中删除集合中对应索引的View对象 */ @Override public void destroyItem(View container, int position, Object object) { ((ViewPager) container).removeView(views.get(position)); } /** * 获取ViewPager的个数 */ @Override public int getCount() { return views.size(); } /** * 从View集合中获取对应索引的元素, 并添加到ViewPager中 */ @Override public Object instantiateItem(View container, final int position) { ((ViewPager) container).addView(views.get(position), 0); // views.get(position).setOnClickListener(new OnClickListener() { // // @Override // public void onClick(View v) { // System.out.println("position"+position); // Intent intent=new Intent(MainActivity.this,OtherViewPage.class); // MainActivity.this.startActivity(intent); // } // }); return views.get(position); } /** * 是否将显示的ViewPager页面与instantiateItem返回的对象进行关联 * 这个方法是必须实现的 */ @Override public boolean isViewFromObject(View view, Object object) { return view == object; } } private class MyAdapter extends BaseAdapter { List<Map<String, Object>> listgrid; private MyAdapter(List<Map<String, Object>> listgrid) { this.listgrid = listgrid; } @Override public int getCount() { return listgrid.size(); } @Override public Object getItem(int position) { return listgrid.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = getLayoutInflater().inflate(R.layout.grid_view_item, null); ImageView getViewLinear = (ImageView) convertView.findViewById(R.id.getViewLinear); getViewLinear.setBackgroundResource(Integer.parseInt(listgrid.get(position).get("image").toString())); return convertView; } } } ``` ``` 只有两个布局文件一个只有上下两个布局里面的ViewPager和小圆点都写在代码里,另一个就是GRIDVIEW的ITEM 经过测试 gridView.setVerticalSpacing(30);只对当前页有效 翻到第二页上下两个图片间距为0,,,gridView.setHorizontalSpacing(5);无效!求解啊!!!!!
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页