关于android:Android-RecyclerView-实现瀑布流

34次阅读

共计 4477 个字符,预计需要花费 12 分钟才能阅读完成。

Android RecyclerView 应用大全 – 根底应用,item 动画,下拉刷新等

瀑布流也是个罕用的显示控件了,然而在应用时常常遇到一些问题,比方滑动回顶部后呈现空隙、item 在滑动时乱跳等问题。

上面就来说说我怎么实现的瀑布流,并且怎么解决下面所说的这些问题的。

我应用了原生控件 RecyclerView+StaggeredGridLayoutManager 来实现的瀑布流,没有用第三方开源框架。上面以 2 列的瀑布流为例子开始解说。

因为应用了 StaggeredGridLayoutManager 实现瀑布流,然而在设置后发现图片在滑动加载过程中高度会发生变化,在网上搜寻了很多材料后,总结解决办法是在 onBindViewHolder 中绑定 View 时,给 ImageView 设置宽高,就能解决这个问题。

先看一下最终实现成果:

失常显示的瀑布流.gif

提前阐明下,我应用的是 Glide3,读者们能够自行批改为 Glide4。

1. 实现瀑布流

先说说实现思路:

  • 写布局文件 ,别离有 2 个布局文件,Activity 的布局文件和 Adapter 的布局文件
  • 写适配器 ,瀑布流的适配器里须要设置 ImageView 的宽高。
  • 写 RecyclerView,给 RecyclerView 设置 StaggeredGridLayoutManager 并设置适配器。
  • 增加数据测试成果 ,依据成果反馈进行批改

第一步:写布局文件

Activity 的布局文件只有一个 RecyclerView 就不贴了,贴一下 Adapter 的布局文件:

adapter_item_card.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/card"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:background="@android:color/holo_green_dark"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/card_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/card_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="2dp"
        tools:text="hello" />
</LinearLayout>

第二步:写适配器

适配器中蕴含数据 Card 的汇合,Card 类蕴含如下几个属性:

    private String title;
    private String img_url;
    private int width;
    private int height;

在适配器中次要就是将数据绑定到 view 上,最要害的步骤是依据图片的宽高算出图片的宽高比,而后依据宽高比抉择正方形显示,还是长方形显示,最初通过 setLayoutParams 办法来设置图片的宽高。

思路如下:

  • 计算图片宽度
  • 依据图片宽高比,确定图片应用正方形或是 4 比 3 的长方形显示
  • 应用 setLayoutParams 办法设置图片宽高
  • 应用 Glide 加载图片并用 override 重写图片宽高

适配器外围代码如下:

private final double STANDARD_SCALE = 1.1; // 当图片宽高比例大于 STANDARD_SCALE 时,采纳 3:4 比例,小于时,则采纳 1:1 比例
private final float SCALE = 4 * 1.0f / 3;       // 图片缩放比例
private List<Card> cards = new ArrayList<>();

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {Card card = mCards.get(position);
    setCardView(holder, card);
}

private void setCardView(ViewHolder holder, Card card) {
    // 计算图片宽高
    LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.image.getLayoutParams();
    // 2 列的瀑布流,屏幕宽度减去两列间的间距 space 所的值再除以 2,计算出单列的 imageview 的宽度,space 的值在 RecyclerView 初始化时传入
    float itemWidth = (ScreenUtil.getScreenWidth(context) - space) / 2;
    layoutParams.width = (int) itemWidth;

    float width = card.getWidth();
    float height = card.getHeight();
    float scale = height / width;
    if (scale > STANDARD_SCALE) {
        // 采纳 3:4 显示
        layoutParams.height = (int) (itemWidth * SCALE);
    } else {
        // 采纳 1:1 显示
        layoutParams.height = (int) itemWidth;
    }
    holder.image.setLayoutParams(layoutParams);
    Glide.with(context).load(card.getImg_url()).asBitmap().placeholder(R.mipmap.ic_launcher)
            .diskCacheStrategy(DiskCacheStrategy.RESULT).centerCrop().into(holder.image);
    holder.title.setText(card.getTitle());
}

写好适配器后,就能够在 MAinActivity 中初始化 RecyclerView 和适配器了,代码如下:

        int space = 20;
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
//        layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);   // 设置后瀑布流不显示了
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setItemAnimator(null);
        mRecyclerView.addItemDecoration(new StaggeredItemDecoration(space));// 单位 px
        mAdapter = new StaggeredGridAdapter(space);
        mAdapter.setCards(mCards);
        mRecyclerView.setAdapter(mAdapter);

在网上看到应用 StaggeredGridLayoutManager 的 setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE) 设置来解决瀑布流滑动到顶部空白的问题,后果发现增加这句代码后,整个瀑布流都不显示了,所以不能这样解决。

在下面的代码中我设置了 space 值,space 是指两列卡片之间的间隔,依据需要设置,这里 space 用在了 2 个中央别离是:

mRecyclerView.addItemDecoration(new StaggeredItemDecoration(space));
mAdapter = new StaggeredGridAdapter(space);

前者用于设置两列瀑布流之间的间隔,后者是用来计算单列图片的宽度。StaggeredItemDecoration 类的代码在此。

代码写好后,来看看瀑布流成果。

如同有点奇怪的中央,在滑动过程中后面图片 1、2、3 的大小产生了变动。我过后也是很纳闷,在网上搜寻图片大小扭转的问题起因也没有找到,如同与 RecyclerView 的图片缓存机制无关,有晓得的胖友能够告知一下。

最初通过在 Glide 加载图片时增加 override 设置图片宽高解决了,对于 override 设置图片能够看看这篇文章《Glide 的 override 办法和 View 的 setLayoutParams 办法设置图片宽高比照》。

Glide.with(context).load(card.getImg_url()).asBitmap().placeholder(R.mipmap.ic_launcher)
                .diskCacheStrategy(DiskCacheStrategy.RESULT).override(layoutParams.width, layoutParams.height).centerCrop().into(holder.image);

解决后的成果如下,能够看到在滑动过程中,图片大小没有再变动:

失常显示的瀑布流.gif

2. 瀑布流顶部呈现空隙、item 乱跳等问题

照下面的解决曾经能解决顶部呈现空隙、item 乱跳的问题,然而倡议在瀑布流更新时采纳 notifyItemRangeInserted() 办法更新,能够防止一些不必要的问题。

if (FIRST_PAGE_LAST_ID.equals(lastId)) {mAdapter.notifyDataSetChanged();// 第一页更新
} else {mAdapter.notifyItemRangeInserted(startPosition, count);// 第一页以外应用 notifyItemRangeInserted() 更新}

如果对你有帮忙的话,点赞、评论、赞叹都是对我的激励,也是反对我写下去的能源,谢谢!

正文完
 0