Android UI 之 RecyclerView 九宫格

Posted Kevin_小飞象

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android UI 之 RecyclerView 九宫格相关的知识,希望对你有一定的参考价值。

基础用法

添加依赖

	// RecyclerAdapter
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
    // glide
    implementation 'com.github.bumptech.glide:glide:4.8.0';
  1. 效果图

  2. 布局文件
    activity_fruit.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.FruitActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_fruit"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

item_fruit

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="80dp"
    android:layout_height="wrap_content"
    android:background="@color/btn_answer_pressed"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_fruit"
        android:layout_width="45dp"
        android:layout_height="45dp"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/ic_apple"/>

    <TextView
        android:id="@+id/tv_fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_gravity="center_horizontal"/>

</LinearLayout>
  1. 分隔线
public class GridDividerItemDecoration extends RecyclerView.ItemDecoration 

    private static final String TAG = "GridDividerItemDeco";

    private Context mContext;

    private int mFirstAndLastColumnW;          //您所需指定的间隔宽度,主要为第一列和最后一列与父控件的间隔;行间距,列间距将动态分配
    private int mFirstRowTopMargin = 0; //第一行顶部是否需要间隔

    private int mLastRowBottomMargin = 0;

    private int mSpanCount = 0;
    private int mScreenW = 0;
    private int mItemDistance;


    /**
     * @param firstAndLastColumnW 间隔宽度
     * @param firstRowTopMargin   第一行顶部是否需要间隔
     */
    public GridDividerItemDecoration(Context context, int firstAndLastColumnW, int firstRowTopMargin, int lastRowBottomMargin) 
        mContext = context;
        mFirstAndLastColumnW = firstAndLastColumnW;
        mFirstRowTopMargin = firstRowTopMargin;
        mLastRowBottomMargin = lastRowBottomMargin;
    


    public void setFirstRowTopMargin(int firstRowTopMargin) 
        mFirstRowTopMargin = firstRowTopMargin;
    

    public void setLastRowBottomMargin(int lastRowBottomMargin) 
        mLastRowBottomMargin = lastRowBottomMargin;
    

    public void setItemDistance(int itemDistance) 
        mItemDistance = itemDistance;
    

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 
        super.getItemOffsets(outRect, view, parent, state);

        int top = 0;
        int left;
        int right;
        int bottom;

        int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        mSpanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();

        // 屏幕宽度-View的宽度*spanCount 得到屏幕剩余空间
        int maxDividerWidth = getMaxDividerWidth(view);
        int spaceWidth = mFirstAndLastColumnW;//首尾两列与父布局之间的间隔
        // 除去首尾两列,item与item之间的距离
        int eachItemWidth = maxDividerWidth / mSpanCount;
        int dividerItemWidth = (maxDividerWidth - 2 * spaceWidth) / (mSpanCount - 1);//item与item之间的距离

        left = itemPosition % mSpanCount * (dividerItemWidth - eachItemWidth) + spaceWidth;

        right = eachItemWidth - left;
        bottom = dividerItemWidth;

        // 首行
        if (mFirstRowTopMargin > 0 && isFirstRow(parent, itemPosition, mSpanCount, childCount)) 
            top = mFirstRowTopMargin;
        

        //最后一行
        if (isLastRow(parent, itemPosition, mSpanCount, childCount)) 
            if (mLastRowBottomMargin < 0) 
                bottom = 0;
             else 
                bottom = mLastRowBottomMargin;
            
        

        Log.i(TAG, "getItemOffsets: dividerItemWidth =" + dividerItemWidth + "eachItemWidth = " + eachItemWidth);

        Log.i(TAG, "getItemOffsets: itemPosition =" + itemPosition + " left = " + left + " top = " + top
                + " right = " + right + " bottom = " + bottom);

        outRect.set(left, top, right, bottom);
    

    /**
     * 获取Item View的大小,若无则自动分配空间
     * 并根据 屏ge幕宽度-View的宽度*spanCount 得到屏幕剩余空间
     *
     * @param view
     * @return
     */
    private int getMaxDividerWidth(View view) 
        int itemWidth = view.getLayoutParams().width;
        int itemHeight = view.getLayoutParams().height;
        Log.i(TAG, "getMaxDividerWidth: itemWidth =" + itemWidth);

        int screenWidth = getScreenWidth();

        int maxDividerWidth = screenWidth - itemWidth * mSpanCount;

        if (itemHeight < 0 || itemWidth < 0 || maxDividerWidth <= (mSpanCount - 1) * mFirstAndLastColumnW) 
            view.getLayoutParams().width = getAttachCloumnWidth();
            view.getLayoutParams().height = getAttachCloumnWidth();
            maxDividerWidth = screenWidth - view.getLayoutParams().width * mSpanCount;
        

        return maxDividerWidth;
    

    private int getScreenWidth() 
        Log.i(TAG, "getScreenWidth: mScreenW =" + mScreenW);
        if (mScreenW > 0) 
            return mScreenW;
        

        mScreenW = mContext.getResources().getDisplayMetrics().widthPixels > mContext.getResources().getDisplayMetrics().heightPixels
                ? mContext.getResources().getDisplayMetrics().heightPixels : mContext.getResources().getDisplayMetrics().widthPixels;
        return mScreenW;
    

    /**
     * 根据屏幕宽度和item数量分配 item View的width和height
     *
     * @return
     */
    private int getAttachCloumnWidth() 
        int itemWidth = 0;
        int spaceWidth = 0;
        try 
            int width = getScreenWidth();
            spaceWidth = 2 * mFirstAndLastColumnW;
            itemWidth = (width - spaceWidth) / mSpanCount - 40;
         catch (Exception e) 
            e.printStackTrace();
        

        return itemWidth;
    

    /**
     * 判读是否是第一列
     *
     * @param parent
     * @param pos
     * @param spanCount
     * @return
     */
    private boolean isFirstColumn(RecyclerView parent, int pos, int spanCount) 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) 
            if (pos % spanCount == 0) 
                return true;
            
         else if (layoutManager instanceof StaggeredGridLayoutManager) 
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) 
                if (pos % spanCount == 0) // 第一列
                    return true;
                
             else 

            
        
        return false;
    

    /**
     * 判断是否是最后一列
     *
     * @param parent
     * @param pos
     * @param spanCount
     * @param childCount
     * @return
     */
    private boolean isLastColumn(RecyclerView parent, int pos, int spanCount) 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) 
            if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边
                return true;
            
         else if (layoutManager instanceof StaggeredGridLayoutManager) 
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) 
                if ((pos + 1) % spanCount == 0) // 最后一列
                    return true;
                
             else 

            
        
        return false;
    

    /**
     * 判读是否是最后一行
     *
     * @param parent
     * @param pos
     * @param spanCount
     * @param childCount
     * @return
     */
    private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) 
            int lines = childCount % spanCount == 0 ? childCount / spanCount : childCount / spanCount + 1;
            return lines == pos / spanCount + 1;
        
        return false;
    

    /**
     * 判断是否是第一行
     *
     * @param parent
     * @param pos
     * @param spanCount
     * @param childCount
     * @return
     */
    private boolean isFirstRow(RecyclerView parent, int pos, int spanCount, int childCount) 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) 
            if ((pos / spanCount + 1) == 1) 
                return true;
             else 
                return false;
            
        
        return false;
    

    /**
     * 获取列数
     *
     * @param parent
     * @return
     */
    private int getSpanCount(RecyclerView parent) 
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) 
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
         else if (layoutManager instanceof StaggeredGridLayoutManager) 
            spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
        
        return spanCount;
    

  1. 适配器
public class FruitAdapter extends BaseQuickAdapter<FruitBean, BaseViewHolder> 

    public FruitAdapter(int layoutResId, @Nullable List<FruitBean> data) 
        super(layoutResId, data);
    

    @Override
    protected void convert(BaseViewHolder helper, FruitBean item) 
        ImageView image = helper.getView(R.id.iv_fruit);
        Glide.with(MyApp.getAppContext())
                .load(item.getIconId())
                .into(image);

        helper.setText(R.id.tv_fruit_name,item.getName());
    

  1. 逻辑代码
public class FruitActivity extends BaseActivity 
    @BindView(R.id.rv_fruit)
    RecyclerView mRecyclerView;

    private FruitAdapter mAdapter;

    @Override
    public int getLayoutId() 
        return R.layout.activity_fruit;
    

    @Override
    public void initView() 
        mAdapter = new FruitAdapter(R.layout.item_fruit,getData());
        mAdapter.openLoadAnimation();
        int firstAndLastColumnW = DensityUtil.dip2px(this, 15);
        int firstRowTopMargin = DensityUtil.dip2px(this, 15);
        GridDividerItemDecoration gridDividerItemDecoration =
                new GridDividerItemDecoration(this, firstAndLastColumnW, firstRowTopMargin, firstRowTopMargin);
        gridDividerItemDecoration.setFirstRowTopMargin(firstRowTopMargin);
        gridDividerItemDecoration.setLastRowBottomMargin(firstRowTopMargin);
        mRecyclerView.addItemDecoration(gridDividerItemDecoration);
        GridLayoutManager layoutManager = new GridLayoutManager(this, 3);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setAdapter(mAdapter);
    

    private List<FruitBean> getData() 
        return Arrays.asList(new FruitBean("apple",R.mipmap.ic_apple),
                new FruitBean("banana",R.mipmap.ic_banana),
                new FruitBean("cherry",R.mipmap.ic_cherry),
                new FruitBean("grape",R.mipmap.ic_grape),
                new FruitBean("mango",R.mipmap.ic_mango),
                new FruitBean("orange",R.mipmap.ic_orange),
                new FruitBean("pear",R.mipmap.ic_pear),
                new FruitBean("pineapple",R.mipmap.ic_pineapple以上是关于Android UI 之 RecyclerView 九宫格的主要内容,如果未能解决你的问题,请参考以下文章

Android UI 之 RecyclerView 九宫格

Android UI 之 RecyclerView 九宫格

Android UI 之 RecyclerView 基础用法

Android UI 之 RecyclerView 瀑布流

Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

Android笔记之UI篇