RecyclerFullyManagerDemo【ScrollView里嵌套Recycleview的自适应高度功能】
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
对于Recyclerview自己的LinearLayoutManager和GridLayoutManager,在版本23.2.0之后的library库中已经解决了自适应的问题;
关于RecyclerView 23.2.0新特性
这个版本给 LayoutManager API 添加了新的特性:自动测量(auto-measurement)!它允许 RecyclerView 根据内容控制高度。
这意味着我们可以实现之前无法实现的情景(比如给 RecyclerView 设置 WRAP_CONTENT 属性)
基于这个改变,请检查 item 视图在之前设置的属性(旧版的 RecyclerView 的 item 视图如果设置 MATCH_PARENT 属性,则会自动占满整个视图)
但是有个问题就是当列表项超过一个屏幕的时候,Recyclerview的高度就是起始位置到屏幕的底部的高度值。
Demo中的FullyGridLayoutManager、FullyLinearLayoutManager、MyStaggeredGridLayoutManager,是在Frank-Zhu/AndroidRecyclerViewDemo基础上进行了优化,解决了上面说到的问题。
效果图
LinearLayoutManager GridLayoutManager
FullyLinearLayoutManager FullyGridLayoutManager
代码分析
使用FullyGridLayoutManager、FullyLinearLayoutManager、MyStaggeredGridLayoutManager的话,需要注意以下两点:
1、布局文件中需要给RecyclerView添加一个父布局LinearLayout【绿色区域是ScrollView的写法,黄色区域是需要注意的】
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F4F4F4"> <!-- 设置区域:可滑动 --> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbarSize="2dp" android:scrollbarThumbVertical="@drawable/scrollbar" android:scrollbars="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="对于系统自己的LinearLayoutManager和GridLayoutManager,在版本23.2.0之后的library库中已经解决了自适应的问题;\n但是有个问题就是当列表项超过一个屏幕的时候,Recyclerview的高度就是起始位置到屏幕的底部的高度值。" android:layout_margin="8dp"/> <!-- 列表区域 --> <LinearLayout android:id="@+id/recycler_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- RecyclerView列表 --> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:cacheColorHint="#00000000" android:divider="@null" android:listSelector="#00000000" android:scrollbars="none" /> </LinearLayout> <Button android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加一个item" android:layout_margin="8dp"/> </LinearLayout> </ScrollView> </RelativeLayout>
2、在代码中需要执行LayoutManager的setRecyclerViewLayout()方法,将RecyclerView的父布局传值过去
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
(1)在build.gradle中引用recyclerview【版本号和appcompat保持一致】
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.why.project.recyclerfullymanagerdemo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
//RecyclerView
compile "com.android.support:recyclerview-v7:27.1.1"
}
(2)在项目中实现Recyclerview基本数据展现
1、创建Bean类
package com.why.project.recyclerfullymanagerdemo.bean; /** * Created by HaiyuKing * Used 列表项的bean类 */ public class NewsBean { private String newsId;//id值 private String newsTitle;//标题 public String getNewsId() { return newsId; } public void setNewsId(String newsId) { this.newsId = newsId; } public String getNewsTitle() { return newsTitle; } public void setNewsTitle(String newsTitle) { this.newsTitle = newsTitle; } }
2、创建Adapter以及item的布局文件【这个Demo中不需要后续修改】
package com.why.project.recyclerfullymanagerdemo.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.why.project.recyclerfullymanagerdemo.R; import com.why.project.recyclerfullymanagerdemo.bean.NewsBean; import java.util.ArrayList; /** * Created by HaiyuKing * Used 列表适配器 */ public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ /**上下文*/ private Context myContext; /**集合*/ private ArrayList<NewsBean> listitemList; /** * 构造函数 */ public NewsAdapter(Context context, ArrayList<NewsBean> itemlist) { myContext = context; listitemList = itemlist; } /** * 获取总的条目数 */ @Override public int getItemCount() { return listitemList.size(); } /** * 创建ViewHolder */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(myContext).inflate(R.layout.news_list_item, parent, false); ItemViewHolder itemViewHolder = new ItemViewHolder(view); return itemViewHolder; } /** * 声明grid列表项ViewHolder*/ static class ItemViewHolder extends RecyclerView.ViewHolder { public ItemViewHolder(View view) { super(view); listItemLayout = (LinearLayout) view.findViewById(R.id.listitem_layout); mChannelName = (TextView) view.findViewById(R.id.tv_channelName); } LinearLayout listItemLayout; TextView mChannelName; } /** * 将数据绑定至ViewHolder */ @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) { //判断属于列表项 if(viewHolder instanceof ItemViewHolder){ NewsBean newsBean = listitemList.get(index); final ItemViewHolder itemViewHold = ((ItemViewHolder)viewHolder); itemViewHold.mChannelName.setText(newsBean.getNewsTitle()); //如果设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { itemViewHold.listItemLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了 mOnItemClickLitener.onItemClick(itemViewHold.listItemLayout, position); } }); //长按事件 itemViewHold.listItemLayout.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了 mOnItemClickLitener.onItemLongClick(itemViewHold.listItemLayout, position); return false; } }); } } } /** * 添加Item--用于动画的展现*/ public void addItem(int position,NewsBean listitemBean) { listitemList.add(position,listitemBean); notifyItemInserted(position); } /** * 删除Item--用于动画的展现*/ public void removeItem(int position) { listitemList.remove(position); notifyItemRemoved(position); } /*=====================添加OnItemClickListener回调================================*/ public interface OnItemClickLitener { void onItemClick(View view, int position); void onItemLongClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/listitem_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_margin="1dp" android:background="#ffffff"> <TextView android:id="@+id/tv_channelName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="标题" android:textSize="18sp" android:padding="20dp"/> </LinearLayout>
3、在Activity布局文件中引用Recyclerview控件【因为该Demo演示的是ScrollView中嵌套RecyclerView,所以布局和普通的RecyclerView不太一样(RecyclerView的高度设置为wrap_content)】
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F4F4F4"> <!-- 设置区域:可滑动 --> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbarSize="2dp" android:scrollbarThumbVertical="@drawable/scrollbar" android:scrollbars="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="对于系统自己的LinearLayoutManager和GridLayoutManager,在版本23.2.0之后的library库中已经解决了自适应的问题;\n但是有个问题就是当列表项超过一个屏幕的时候,Recyclerview的高度就是起始位置到屏幕的底部的高度值。" android:layout_margin="8dp"/> <!-- 列表区域 --> <LinearLayout android:id="@+id/recycler_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- RecyclerView列表 --> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:cacheColorHint="#00000000" android:divider="@null" android:listSelector="#00000000" android:scrollbars="none" /> </LinearLayout> <Button android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加一个item" android:layout_margin="8dp"/> </LinearLayout> </ScrollView> </RelativeLayout>
4、在Activity类中初始化recyclerview数据
package com.why.project.recyclerfullymanagerdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import com.why.project.recyclerfullymanagerdemo.adapter.NewsAdapter; import com.why.project.recyclerfullymanagerdemo.bean.NewsBean; import java.util.ArrayList; /** * Created by HaiyuKing * Used */ public class LinearLayoutManagerActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private ArrayList<NewsBean> mNewsBeanArrayList; private NewsAdapter mNewsAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recyclerview); initViews(); initDatas(); initEvents(); } private void initViews() { mRecyclerView = findViewById(R.id.recycler_view); } private void initDatas() { //初始化集合 mNewsBeanArrayList = new ArrayList<NewsBean>(); for(int i=0; i<5;i++){ NewsBean newsBean = new NewsBean(); newsBean.setNewsId("123"+i); newsBean.setNewsTitle("标题"+i); mNewsBeanArrayList.add(newsBean); } //设置布局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(linearLayoutManager); //设置适配器 if(mNewsAdapter == null){ //设置适配器 mNewsAdapter = new NewsAdapter(this, mNewsBeanArrayList); mRecyclerView.setAdapter(mNewsAdapter); //添加分割线 //设置添加删除动画 //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局 mRecyclerView.setSelected(true); }else{ mNewsAdapter.notifyDataSetChanged(); } } private void initEvents() { //列表适配器的点击监听事件 mNewsAdapter.setOnItemClickLitener(new NewsAdapter.OnItemClickLitener() { @Override public void onItemClick(View view, int position) { } @Override public void onItemLongClick(View view, int position) { } }); //添加一个item findViewById(R.id.btn_add).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NewsBean newsBean = new NewsBean(); newsBean.setNewsId("123"+20); newsBean.setNewsTitle("标题"+20); mNewsBeanArrayList.add(newsBean); mNewsAdapter.notifyDataSetChanged(); } }); } }
(3)将manager包复制到项目中
package com.why.project.recyclerfullymanagerdemo.manager; import android.content.Context; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; /** * Author: ZhuWenWu * Version V1.0 * Date: 2015/2/26 14:14. * Description: * Modification History: * Date Author Version Description * ----------------------------------------------------------------------------------- * 2015/2/26 ZhuWenWu 1.0 1.0 * Why & What is modified: * 【在原有的基础上进行了优化】 */ public class FullyGridLayoutManager extends GridLayoutManager { private static final String TAG = FullyGridLayoutManager.class.getSimpleName(); private LinearLayout mRecyclerViewLayout;//实现固定recyclerview的父布局的高度值 public FullyGridLayoutManager(Context context, int spanCount) { super(context, spanCount); } public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; int count = getItemCount(); int span = getSpanCount(); Log.d(TAG,"{onMeasure}count="+count+";span="+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), mMeasuredDimension); if (getOrientation() == HORIZONTAL) { if (i % span == 0) { width = width + mMeasuredDimension[0]; } if (i == 0) { height = mMeasuredDimension[1]; } } else { if (i % span == 0) { height = height + mMeasuredDimension[1]; } if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } Log.w(TAG,"{onMeasure}width="+width+";height="+height); setMeasuredDimension(width, height); //实现固定recyclerview的父布局的高度值 LinearLayout.LayoutParams parmas = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height); mRecyclerViewLayout.setLayoutParams(parmas); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { Log.d(TAG,"{measureScrapChild}position="+position+";getItemCount()="+getItemCount()); if (position < getItemCount()) { try { View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); Log.w(TAG,"{measureScrapChild}childWidthSpec="+childWidthSpec+";childHeightSpec="+childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; Log.w(TAG,"{measureScrapChild}measuredDimension[0]="+measuredDimension[0]+";measuredDimension[1]="+measuredDimension[1]); recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } } } //实现固定recyclerview的父布局的高度值 public LinearLayout getRecyclerViewLayout() { return mRecyclerViewLayout; } public void setRecyclerViewLayout(LinearLayout recyclerViewLayout) { mRecyclerViewLayout = recyclerViewLayout; } //实现禁止recyclerview滑动 @Override public boolean canScrollVertically() { //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll return false && super.canScrollVertically(); } }
package com.why.project.recyclerfullymanagerdemo.manager; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; /** * @Created HaiyuKing * @Used RecyclerView和ScrollView嵌套使用【在原有的基础上进行了优化】 * http://www.cnblogs.com/tianzhijiexian/p/4469516.html */ public class FullyLinearLayoutManager extends LinearLayoutManager { private static final String TAG = FullyLinearLayoutManager.class.getSimpleName(); private LinearLayout mRecyclerViewLayout;//实现固定recyclerview的父布局的高度值 public FullyLinearLayoutManager(Context context) { super(context); } public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); Log.i(TAG, "onMeasure called. \nwidthMode " + widthMode + " \nheightMode " + heightSpec + " \nwidthSize " + widthSize + " \nheightSize " + heightSize + " \ngetItemCount() " + getItemCount()); int width = 0; int height = 0; for (int i = 0; i < getItemCount(); i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); if (getOrientation() == HORIZONTAL) { width = width + mMeasuredDimension[0]; if (i == 0) { height = mMeasuredDimension[1]; } } else { height = height + mMeasuredDimension[1]; if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); //实现固定recyclerview的父布局的高度值 LinearLayout.LayoutParams parmas = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height); mRecyclerViewLayout.setLayoutParams(parmas); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { try { View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } finally { } } //实现固定recyclerview的父布局的高度值 public LinearLayout getRecyclerViewLayout() { return mRecyclerViewLayout; } public void setRecyclerViewLayout(LinearLayout recyclerViewLayout) { mRecyclerViewLayout = recyclerViewLayout; } //实现禁止recyclerview滑动 @Override public boolean canScrollVertically() { //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll return false && super.canScrollVertically(); } }
package com.why.project.recyclerfullymanagerdemo.manager; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.LinearLayout; /** * @Created HaiyuKing * @Used StaggeredGridLayoutManager自适应高度 * http://blog.csdn.net/skyyywerq/article/details/50731134 */ public class MyStaggeredGridLayoutManager extends StaggeredGridLayoutManager { private static final String TAG = MyStaggeredGridLayoutManager.class.getSimpleName(); private LinearLayout mRecyclerViewLayout;//实现固定recyclerview的父布局的高度值 public MyStaggeredGridLayoutManager(int spanCount, int orientation, Context mContext) { super(spanCount, orientation); mHeightArray = new int[spanCount]; this.mContext = mContext; for (int i = 0; i < spanCount; i++) mHeightArray[i] = 0; } private int[] mMeasuredDimension = new int[2]; private int[] mHeightArray; private Context mContext; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; int count = getItemCount(); int span = getSpanCount(); for (int i = 0; i < span; i++)//防止多次调用onMeasure方法造成数据叠加 mHeightArray[i] = 0; for (int i = 0; i < count; i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); if (getOrientation() == HORIZONTAL) calculatorStaggeredHeight(mMeasuredDimension[0]); else calculatorStaggeredHeight(mMeasuredDimension[1]); } //获取屏幕高度和宽度 WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); if (getOrientation() == HORIZONTAL) { width = sort(mHeightArray); height = outMetrics.widthPixels;//获取屏幕高度 } else { height = sort(mHeightArray); width = outMetrics.heightPixels;//获取屏幕宽度 } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); //实现固定recyclerview的父布局的高度值 LinearLayout.LayoutParams parmas = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height); mRecyclerViewLayout.setLayoutParams(parmas); } /** * 冒泡排序返回数组最大值 * * @param unsorted * @return */ private int sort(int[] unsorted) { for (int i = 0; i < unsorted.length; i++) { for (int j = i; j < unsorted.length; j++) { if (unsorted[i] < unsorted[j]) { int temp = unsorted[i]; unsorted[i] = unsorted[j]; unsorted[j] = temp; } } } return unsorted[0]; } /** * 将传入的item高度值赋给当前数组中最小的元素 * * @param singleViewHeight 传入的item高度 */ private void calculatorStaggeredHeight(int singleViewHeight) { int index = 0; int minValue = mHeightArray[0]; for (int i = 1; i < mHeightArray.length; i++) { if (minValue > mHeightArray[i]) { minValue = mHeightArray[i]; index = i; } } mHeightArray[index] += singleViewHeight; } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { if (position < getItemCount()) { try { View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; Log.v("p.height", p.height + ""); Log.v("measuredDimension[1]", measuredDimension[1] + ""); recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } } } //实现固定recyclerview的父布局的高度值 public LinearLayout getRecyclerViewLayout() { return mRecyclerViewLayout; } public void setRecyclerViewLayout(LinearLayout recyclerViewLayout) { mRecyclerViewLayout = recyclerViewLayout; } //实现禁止recyclerview滑动 @Override public boolean canScrollVertically() { //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll return false && super.canScrollVertically(); } }
三、使用方法
FullyGridLayoutManager、FullyLinearLayoutManager、MyStaggeredGridLayoutManager的使用方法,就是替换掉之前项目中使用设置布局管理器代码部分的GridLayoutManager、LinearLayoutManager、StaggeredGridLayoutManager。
比如使用FullyGridLayoutManager的话,就按照下面的进行替换:
混淆配置
无
参考资料
ScrollView里嵌套Recycleview使用StaggeredGridLayoutManager高度不正确的问题
Frank-Zhu/AndroidRecyclerViewDemo