RecyclerView利用GridLayoutManager实现少于span数量时候居中对齐

这里不是直接讲怎么实现GridLayoutManager的居中对齐事情。
原始需求是这样的:
每行显示4个标签,当有超过4个item时左对齐,但当item少于4个时候要居中对齐,并且大小不变间距不变。一下图片:
5个item

3个item

先要知道public GridLayoutManager(Context context, int spanCount)中spanCount的值一旦设定好了,那么item的大小就确定了。那么当有少于spanCount的数据时,也只是占据靠左的几个span。
为了以下分析,我们设定每行4个item。
首先想到是判断数据个数少于4,那么我们就重新设定spanCount为实际个数,例如3。但是这么做是把原有的大小平均分成了3份,但是不能解决每个item大小不变,间距不变的问题。所以不行。
我这个方法是利用public static abstract class SpanSizeLookup这个来实现,作用是可以重新设定每个item锁占用的span数。例如可以设定一个item占用2个span,那么itme的width就变成2倍的。
先讲下实现原理。
那么一行出现的数据情况是1个、2个、3个、4个,那就4*3*2*1=24。设定spanCount为24。

000102030405060708091011121314151617181920212223
000000111111222222333333
000000000111111222222222
000000000000111111111111
000000000000000000000000

表格简单展示了在不懂数量下,每个item所站的span数量。
具体定义方式如下。

int[][] count = {{24,0,0,0},{12,12,0,0},{9,6,9,0},{6,6,6,6}};

现在不同数量的item的width已经确定了,那么要利用间距来实现item的显示width保持一致。例如item的width理论是4个span,那么当width大于4个span时,那么久设置这个item的边距使得他的现实width变成4个span。
先上代码
主TestActivity

package com.holy.demo.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import com.holy.demo.R;
import com.holy.demo.constant.TestItemDecoration;

import java.util.ArrayList;
import java.util.List;

/**
 * Copyright 2017, Smart Haier. All rights reserved.
 * Description:
 * Author: hanhongliang@smart-haier.com (Han Holy)
 * Date: 2017/10/23
 * ModifyBy:
 * ModifyDate:
 * ModifyDes :
 */

public class TestActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView mTestList;
    private TestAdapter mTestAdapter;
    private GridLayoutManager layoutManager;
    private TestItemDecoration mItemDecoration;
    private final int mListNum = 3;
    private final int mSpanSize = 24;
    private final int mSpanShowSize = 4;
    private int SpanCounts = mSpanSize;
    private List<String> mData;
    private Button testadd, testromove;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        testadd = (Button) findViewById(R.id.testadd);
        testromove = (Button) findViewById(R.id.testromove);
        initData();
        testadd.setOnClickListener(this);
        testromove.setOnClickListener(this);

        mTestList = (RecyclerView) findViewById(R.id.testlist);
        layoutManager = new GridLayoutManager(TestActivity.this, mSpanSize);
        SpanCounts = mData.size()<mSpanShowSize?mData.size():mSpanShowSize;
        layoutManager.setSpanSizeLookup(new TestSpanSizeLookup(SpanCounts));
        mTestList.setLayoutManager(layoutManager);
        mTestList.addItemDecoration(mItemDecoration = new TestItemDecoration(SpanCounts,mSpanShowSize, 30));
        mTestList.setAdapter(mTestAdapter = new TestAdapter());
    }

    public List<String> initData() {
        mData = new ArrayList<>();
        for (int i = 0; i < mListNum; i++) {
            mData.add(Integer.toString(i));
        }
        return mData;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.testadd:
                if (layoutManager != null) {
                    mData.add(Integer.toString(mData.size()));
                    SpanCounts = mData.size()<mSpanShowSize?mData.size():mSpanShowSize;
                    layoutManager.setSpanSizeLookup(new TestSpanSizeLookup(SpanCounts));
                    mTestList.setLayoutManager(layoutManager);
                    mTestList.removeItemDecoration(mItemDecoration);
                    mTestList.addItemDecoration(mItemDecoration = new TestItemDecoration(SpanCounts, mSpanShowSize,30));
                    mTestList.setAdapter(mTestAdapter = new TestAdapter());
                }
                break;
            case R.id.testromove:
                if (layoutManager != null) {
                    mData.remove(mData.size() - 1);
                    SpanCounts = mData.size()<mSpanShowSize?mData.size():mSpanShowSize;
                    layoutManager.setSpanSizeLookup(new TestSpanSizeLookup(SpanCounts));
                    mTestList.setLayoutManager(layoutManager);
                    mTestList.removeItemDecoration(mItemDecoration);
                    mTestList.addItemDecoration(mItemDecoration = new TestItemDecoration(SpanCounts,mSpanShowSize, 30));
                    mTestList.setAdapter(mTestAdapter = new TestAdapter());
                }
                break;
        }
    }

    public class TestViewHolder extends RecyclerView.ViewHolder {
        TextView v;

        public TestViewHolder(View itemView) {
            super(itemView);
            v = (TextView) itemView.findViewById(R.id.item_test);
        }
    }


    public class TestAdapter extends RecyclerView.Adapter<TestViewHolder> {

        @Override
        public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            TestViewHolder holder = new TestViewHolder(LayoutInflater.from(TestActivity.this).inflate(R.layout.item_test, parent, false));
            return holder;
        }

        @Override
        public void onBindViewHolder(TestViewHolder holder, int position) {
            holder.v.setText(mData.get(position));
        }

        @Override
        public int getItemCount() {
            return mData.size();
        }
    }

    public class TestSpanSizeLookup extends GridLayoutManager.SpanSizeLookup{
        int spanCount =0;

        public TestSpanSizeLookup(int spanCount) {
            this.spanCount = spanCount;
        }

        @Override
        public int getSpanSize(int position) {
            int[][] count = {{24,0,0,0},{12,12,0,0},{9,6,9,0},{6,6,6,6}};
            int tmp = position%spanCount;
            return  count[spanCount-1][tmp];
        }
    }




}

主activity_test.xml

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

    <android.support.v7.widget.RecyclerView
        android:layout_marginTop="@dimen/h2"
        android:id="@+id/testlist"
        android:layout_width="@dimen/w85"
        android:layout_height="@dimen/h80"
        android:layout_gravity="center">

    </android.support.v7.widget.RecyclerView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="@dimen/h2"
        android:gravity="center">
        <Button
            android:id="@+id/testadd"
            android:layout_width="@dimen/w30"
            android:layout_height="wrap_content"
            android:background="@drawable/button_shape"
            android:text="add"
            android:textSize="@dimen/h2"/>
        <Button
            android:layout_marginLeft="@dimen/w5"
            android:id="@+id/testromove"
            android:layout_width="@dimen/w30"
            android:layout_height="wrap_content"
            android:background="@drawable/button_shape"
            android:text="romove"
            android:textSize="@dimen/h2"/>
    </LinearLayout>

</LinearLayout>

item样式item_test.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
    <TextView
        android:id="@+id/item_test"
        android:layout_width="match_parent"
        android:layout_height="@dimen/h5"
        android:layout_gravity="center"
        android:layout_marginBottom="@dimen/h0.5"
        android:gravity="center"
        android:background="@drawable/item_shape"
        android:text="123"
        android:textSize="@dimen/h3"/>

</LinearLayout>

边距设置TestItemDecoration

package com.holy.demo.constant;

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Copyright 2017, Smart Haier. All rights reserved.
 * Description:
 * Author: hanhongliang@smart-haier.com (Han Holy)
 * Date: 2017/10/23
 * ModifyBy:
 * ModifyDate:
 * ModifyDes :
 */

public class TestItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private int spanSize;


    public TestItemDecoration(int spanCount, int spanSize, int spacing) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.spanSize = spanSize;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        int column = position % spanCount; // item c
        int width = parent.getWidth();
        int childWidth = (width/spanSize)-spacing;
        int tmp = (width-spacing*(spanCount-1)-childWidth*spanCount)/2;

        if(spanCount == 1){
            outRect.left = tmp; //
            outRect.right = tmp; //
        }else {
            if (column == 0) {
                outRect.left = tmp; //
                outRect.right = spacing / 2;
            } else if (column == (spanCount - 1)) {
                outRect.left = spacing / 2; //
                outRect.right = tmp;
            } else {
                outRect.left = spacing / 2; //
                outRect.right = spacing / 2;
            }
        }

        if (position >= spanCount) {
            outRect.top = spacing / 2; // item top
        }
    }
}

以上代码中有item和button样式的shape,自己可以先去掉。xml文件中涉及到的w或h开头的尺寸值时请替换

以下是解释:
1、设置layoutmanager,mSpanSize常量24;

layoutManager = new GridLayoutManager(TestActivity.this, mSpanSize);

2、SpanSizeLookup重写这个类;按照数据的个数,以及当前item的编号,来返回其所占用的span个数。

public class TestSpanSizeLookup extends GridLayoutManager.SpanSizeLookup{
        int spanCount =0;

        public TestSpanSizeLookup(int spanCount) {
            this.spanCount = spanCount;
        }

        @Override
        public int getSpanSize(int position) {
            int[][] count = {{24,0,0,0},{12,12,0,0},{9,6,9,0},{6,6,6,6}};
            int tmp = position%spanCount;
            return  count[spanCount-1][tmp];
        }
    }

3、重新设定setSpanSizeLookup。SpanCounts是实际上每行显示的个数,应该根据实际数据数量来判断。

layoutManager.setSpanSizeLookup(new TestSpanSizeLookup(SpanCounts));
SpanCounts = mData.size()<mSpanShowSize?mData.size():mSpanShowSize;

4、计算item的边距

@Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item 编号
        int column = position % spanCount; // item 列数
        int width = parent.getWidth();// RecyclerView的宽度
        int childWidth = (width/spanSize)-spacing;// item的显示宽度
        int tmp = (width-spacing*(spanCount-1)-childWidth*spanCount)/2;// 最左和最右的边距

        if(spanCount == 1){
            outRect.left = tmp; //
            outRect.right = tmp; //
        }else {
            if (column == 0) {
                outRect.left = tmp; //
                outRect.right = spacing / 2;
            } else if (column == (spanCount - 1)) {
                outRect.left = spacing / 2; //
                outRect.right = tmp;
            } else {
                outRect.left = spacing / 2; //
                outRect.right = spacing / 2;
            }
        }

        if (position >= spanCount) {
            outRect.top = spacing / 2; // item top
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值