使用RecyclerView實(shí)現(xiàn)瀑布流高度自適應(yīng)
使用RecyclerView實(shí)現(xiàn)的瀑布流高度自適應(yīng),供大家參考,具體內(nèi)容如下
背景:使用時在RecyclerView外嵌套了自定義的ScrollView,需要讓RecyclerView高度自適應(yīng),由于是瀑布流格式網(wǎng)上找了好多方法都無法實(shí)現(xiàn)或是動態(tài)計算的高度不準(zhǔn)確。估計大家都知道recyclerview 內(nèi)容的高度不是 recyclerview 控制的而是由LayoutManager 來設(shè)置的。下面我來說下我的解決方案吧:
布局中的使用
<android.support.v7.widget.RecyclerView
android:id="@+id/rcv_indexfragment_article_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen12"
android:padding="@dimen/dimen4"
android:background="@color/bg_white"/>
方法一
個人認(rèn)為最簡單有效的方法,解決問題最終選用的方法。
官網(wǎng)博客翻譯資料:
RecyclerView 控件提供了靈活一種創(chuàng)建列表和網(wǎng)格的基本方案,而且還支持動畫。這個版本為 LayoutManager API帶來了一個非常激動人心的新特性:自動測量!讓RecyclerView可以根據(jù)其內(nèi)容的大小調(diào)整自己。這意味著以前那些無解的場景,比如對RecyclerView的一個dimension 使用WRAP_CONTENT成為了可能。你會發(fā)現(xiàn)所有的內(nèi)置LayoutManager現(xiàn)在都支持自動測量。
因?yàn)檫@個變化的原因,你得仔細(xì)檢查 item view的 layout parameters 了:以前會被自動忽略的 layout parameters(比如在滾動方向上的MATCH_PARENT ),現(xiàn)在會被完全考慮進(jìn)去。如果你有一個自定義的LayoutManager,且沒有繼承自內(nèi)置的LayoutManager,那么這就是一個可選的API - 你需要調(diào)用setAutoMeasureEnabled(true) 并且根據(jù)這個方法的Javadoc中的描述做一些微小的改變。
注意,雖然RecyclerView可以讓自己的子View動畫,但是它不能動畫自己的邊界改變。如果你想要讓RecyclerView的邊界變化也呈現(xiàn)動畫,你可以使用 Transition API。
配置的版本:
compile 'com.android.support:recyclerview-v7:23.2.1'
想要內(nèi)容隨高度變化需設(shè)置:(注意:此方式是Android Support Library 23.2中引入的,如果配置之前的版本會報錯哦~)
layoutManager.setAutoMeasureEnabled(true);
Activity中的使用:
recyclerview= ViewFindUtils.find(view, R.id.recyclerview);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
layoutManager.setAutoMeasureEnabled(true);
recyclerview.setLayoutManager(layoutManager);
recyclerview.setHasFixedSize(true);
recyclerview.setNestedScrollingEnabled(false);
SpacesItemDecoration decoration = new SpacesItemDecoration(6);
recyclerview.addItemDecoration(decoration);
方法二
自定義CustomStaggeredGridLayoutManager類繼承自StaggeredGridLayoutManager。(注:此方法用到我的項目中計算的高度不準(zhǔn)確,列表后面總有一段空白,所以我放棄了~不過你們可以試試,可能是我布局嵌套的問題)
配置的版本(建議使用最新的版本):
compile 'com.android.support:recyclerview-v7:23.1.1'
Activity中的使用:
recyclerview= ViewFindUtils.find(view, R.id.recyclerview); CustomStaggeredGridLayoutManager layoutManager = new CustomStaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL); recyclerview.setLayoutManager(layoutManager); recyclerview.setHasFixedSize(true); recyclerview.setNestedScrollingEnabled(false); SpacesItemDecoration decoration = new SpacesItemDecoration(6); recyclerview.addItemDecoration(decoration);
SpacesItemDecoration.class
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.top = space;
outRect.bottom = space;
outRect.left = space;
outRect.right = space;
}
}
CustomStaggeredGridLayoutManager.class
package com.sunny.demo.widget;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.ViewGroup;
import com.parkmecn.ehc.utils.LogUtil;
/**
* 解決ScrollView嵌套RecyclerView時RecyclerView需要高度自適應(yīng)的問題
*/
public class CustomStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
public CustomStaggeredGridLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
}
// 尺寸的數(shù)組,[0]是寬,[1]是高
private int[] measuredDimension = new int[2];
// 用來比較同行/列那個item罪寬/高
private int[] dimension;
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
// 寬的mode+size
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
// 高的mode + size
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
// 自身寬高的初始值
int width = 0;
int height = 0;
// item的數(shù)目
int count = getItemCount();
// item的列數(shù)
int span = getSpanCount();
// 根據(jù)行數(shù)或列數(shù)來創(chuàng)建數(shù)組
dimension = new int[span];
for (int i = 0; i < count; i++) {
measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View
.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredDimension);
// 如果是豎直的列表,計算item的高,否則計算寬度
// LogUtil.d("LISTENER", "position " + i + " height = " + measuredDimension[1]);
if (getOrientation() == VERTICAL) {
dimension[findMinIndex(dimension)] += measuredDimension[1];
} else {
dimension[findMinIndex(dimension)] += measuredDimension[0];
}
}
if (getOrientation() == VERTICAL) {
height = findMax(dimension);
} else {
width = findMax(dimension);
}
switch (widthMode) {
// 當(dāng)控件寬是match_parent時,寬度就是父控件的寬度
case View.MeasureSpec.EXACTLY:
width = widthSize;
break;
case View.MeasureSpec.AT_MOST:
break;
case View.MeasureSpec.UNSPECIFIED:
break;
}
switch (heightMode) {
// 當(dāng)控件高是match_parent時,高度就是父控件的高度
case View.MeasureSpec.EXACTLY:
height = heightSize;
break;
case View.MeasureSpec.AT_MOST:
break;
case View.MeasureSpec.UNSPECIFIED:
break;
}
// 設(shè)置測量尺寸
setMeasuredDimension(width, height);
LogUtil.e("setMeasuredDimension(width, height)--->height==" + height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[]
measuredDimension) {
// 挨個遍歷所有item
if (position < getItemCount()) {
try {
View view = recycler.getViewForPosition(position);//fix 動態(tài)添加時報IndexOutOfBoundsException
if (view != null) {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight
(), lp.width);
LogUtil.e(position + "--->heightSpec=" + heightSpec + ";getPaddingTop()=" + getPaddingTop() + ";" +
"getPaddingBottom()" + getPaddingBottom() + ";lp.height=" + lp.height);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() +
getPaddingBottom(), lp.height);
LogUtil.e(position + "--->viewchildHeightSpec=" + childHeightSpec);
// 子view進(jìn)行測量,然后可以通過getMeasuredWidth()獲得測量的寬,高類似
view.measure(childWidthSpec, childHeightSpec);
// 將item的寬高放入數(shù)組中
measuredDimension[0] = view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
//FIXME 此處計算的高度總比實(shí)際高度要高一些,導(dǎo)致最后RecycerView的高度計算不對最后留有一段空白,暫時沒有找到問題所在,待大神的解決啊~
measuredDimension[1] = view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
LogUtil.e(position + "--->view.getMeasuredHeight()=" + view.getMeasuredHeight() + ";lp" +
".topMargin=" + lp.topMargin + ";lp.bottomMargin=" + lp.bottomMargin);
recycler.recycleView(view);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private int findMax(int[] array) {
int max = array[0];
for (int value : array) {
if (value > max) {
max = value;
}
}
return max;
}
/**
* 得到最數(shù)組中最小元素的下標(biāo)
*
* @param array
* @return
*/
private int findMinIndex(int[] array) {
int index = 0;
int min = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
index = i;
}
}
return index;
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ListView實(shí)現(xiàn)下拉刷新加載更多的實(shí)例代碼(直接拿來用)
這篇文章主要介紹了ListView實(shí)現(xiàn)下拉刷新加載更多的實(shí)例代碼(直接拿來用)的相關(guān)資料,需要的朋友可以參考下2016-07-07
Android中通過ActionBar為標(biāo)題欄添加搜索及分享視窗
這篇文章主要介紹了ANDROID中通過ACTIONBAR為標(biāo)題欄添加搜索以及分享視窗的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android開發(fā)實(shí)現(xiàn)消除屏幕鎖的方法
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)消除屏幕鎖的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android鎖屏的原理及消除屏幕鎖的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
Android6.0來電號碼與電話薄聯(lián)系人進(jìn)行匹配
這篇文章主要為大家詳細(xì)介紹了Android6.0來電號碼與電話薄聯(lián)系人進(jìn)行匹配的方法,感興趣的小伙伴們可以參考一下2016-07-07
利用adt-bundle輕松搭建Android開發(fā)環(huán)境與Hello world(Linux)
這篇文章主要介紹了利用adt-bundle在Linux下輕松搭建Android開發(fā)環(huán)境與Hello world,感興趣的小伙伴們可以參考一下2016-07-07
Android垂直切換的圓角Banner與垂直指示器相關(guān)介紹與應(yīng)用詳解
這篇文章主要介紹了Android垂直切換的圓角Banner與垂直指示器相關(guān)介紹與應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10
androidstudio3.0使用butterknife報錯解決的解決方法
這篇文章主要介紹了androidstudio3.0使用butterknife報錯解決的解決方法,非常具有實(shí)用價值,需要的朋友可以參考下2018-01-01

