使用 LayoutManger 打造 RecyclerView 多种 ItemType 布局——MultiItemLayoutManger

简介

随着 RecyclerView 控件的发布,已经有越来越多的人开始放弃 ListView 而转向 RecyclerView。
RecyclerView 已经被人玩出了各种花样,但是关于多种布局的 ItemView 的实现网上的资料还是很少,多种布局的 ItemView 其实使用场景非常多,只不过因为有很多代替方案所以可能会很少有人会使用 RecyclerView 来实现,比如下面这样:

预览图
包括图中的 Banner ,子标题,按钮等所有的元素都是通过一个 RecyclerView 来实现的,苦于没找到相关博客只能自己写一个了,其实还是很简单的,下面来看一下实现方式。或者直接[查看代码](https://github.com/0xZhangKe/Collection/tree/master/MultiItemLayoutManger)。 # 实现方式 在 Adapter 中有关于设置 ItemViewType 的方法,但是仅仅通过设置 Adapter 并不能实现上面的功能,还需要结合 LayoutManager 来实现,这是因为子 View 的大小及位置是由 LayoutManager 负责管理。按照上面的样式需要三个 ItemViewType,如下: ```java public static final int BANNER_ITEM_TYPE = 0; public static final int TITLE_ITEM_TYPE = 1; public static final int MENU_ITEM_TYPE = 2; ``` 这里之所以使用 public static 修饰是因为这三个属性 Adapter 中也需要使用。 下面需要根据这三种 Type 来分别设置子 View: ```java @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { if (getItemCount() <= 0 || state.isPreLayout()) { return; } detachAndScrapAttachedViews(recycler);
int curWidth = 0, curLineTop = 0;
int horizontalCount = 0;//横向已经摆放的个数
int widthDivider = -1;//横向间隔
int lastViewType = MENU_ITEM_TYPE;//上一个 View 的类型
int lastHeight = 0;//上一个 View 的高度
for (int i = 0; i < getItemCount(); i++) {
    //遍历所有的子 View 进行计算处理
    View view = recycler.getViewForPosition(i);
    addView(view);

    measureChildWithMargins(view, 0, 0);

    //获取当前 View 的大小
    int width = getDecoratedMeasuredWidth(view);
    int height = getDecoratedMeasuredHeight(view);

    int viewType = getItemViewType(view);

    if (viewType == TITLE_ITEM_TYPE || viewType == BANNER_ITEM_TYPE) {
        //Banner 和子标题宽度及摆放方式其实是相同的,这里不做区分
        if (i != 0) {
            curLineTop += lastHeight;
        }
        layoutDecorated(view, 0, curLineTop, width, curLineTop + height);
        horizontalCount = 0;
        curWidth = 0;
        lastHeight = height;
        lastViewType = viewType;
    } else {
        if (widthDivider == -1) {
            widthDivider = (getWidth() - width * spanCount) / (spanCount + 1);
        }
        if (horizontalCount >= spanCount) {
            //需要换行
            curLineTop += lastHeight;//高度需要改变
            layoutDecorated(view, widthDivider, curLineTop, widthDivider + width, curLineTop + height);
            horizontalCount = 1;
            curWidth = width + widthDivider * 2;
            lastHeight = height;
            lastViewType = viewType;
        } else {
            //未换行,高度不变,横向距离变化
            if (curWidth == 0) {
                curWidth = widthDivider;
            }
            if(i != 0 && lastViewType != MENU_ITEM_TYPE){
                curLineTop += lastHeight;
            }
            layoutDecorated(view, curWidth, curLineTop, curWidth + width, curLineTop + height);
            curWidth += width + widthDivider;
            horizontalCount++;
            lastHeight = height;
            lastViewType = viewType;
        }
    }
    if(i == getItemCount() - 1){
        curLineTop += lastHeight;
    }
}
//计算总高度,滑动时需要使用
totalHeight = Math.max(curLineTop, getVerticalSpace());
verticalScrollOffset = 0;

}

上面的注释写的很清楚了,还是比较简单的,除此之外还需要使 RecyclerView 可以上下滑动:
```java
@Override
public boolean canScrollVertically() {
    return true;
}

@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
    int travel = dy;
    if (verticalScrollOffset + dy < 0) {
        travel = -verticalScrollOffset;
    } else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//如果滑动到最底部
        travel = totalHeight - getVerticalSpace() - verticalScrollOffset;
    }
    verticalScrollOffset += travel;
    offsetChildrenVertical(-travel);
    return travel;
}

下面当上全部代码:

package com.zhangke.widget;

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

/**
 * 多种 ItemView 布局的 LayoutManger
 * <p>
 * Created by ZhangKe on 2018/4/8.
 */
public class MultiItemLayoutManger extends RecyclerView.LayoutManager {
   

    public static final int BANNER_ITEM_TYPE = 0;
    public static final int TITLE_ITEM_TYPE = 1;
    public
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值