Android RecycleView高度自适应

高度自适应

RecycleView的高度为wrap_content 并且item的高度也是wrap_content时 RecycleView的高度就不会根据内容自动设置

解决方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context) {
super(context);
}

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}

public MyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}


@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
// 先把所有的View先从RecyclerView中detach掉,然后标记为"Scrap"状态,表示这些View处于可被重用状态(非显示中)。
// 实际就是把View放到了Recycler中的一个集合中。
detachAndScrapAttachedViews(recycler);
calculateChildrenSite(recycler);
}

int totalHeight = 0;

private void calculateChildrenSite(RecyclerView.Recycler recycler) {
totalHeight = 0;
for (int i = 0; i < getItemCount(); i++) {
// 遍历Recycler中保存的View取出来
View view = recycler.getViewForPosition(i);
addView(view); // 因为刚刚进行了detach操作,所以现在可以重新添加
measureChildWithMargins(view, 0, 0); // 通知测量view的margin值
int width = getDecoratedMeasuredWidth(view); // 计算view实际大小,包括了ItemDecorator中设置的偏移量。
int height = getDecoratedMeasuredHeight(view);

Rect mTmpRect = new Rect();
//调用这个方法能够调整ItemView的大小,以除去ItemDecorator。
calculateItemDecorationsForChild(view, mTmpRect);

// 调用这句我们指定了该View的显示区域,并将View显示上去,此时所有区域都用于显示View,
//包括ItemDecorator设置的距离。
layoutDecorated(view, 0, totalHeight, width, totalHeight + height);
totalHeight += height;
}
}

}

RecycleView

添加引用

1
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'

数据适配器Adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BookAdapter(data: MutableList<CollBookBean>) :
BaseQuickAdapter<CollBookBean, BaseViewHolder>(R.layout.s_book_item, data) {

override fun convert(helper: BaseViewHolder, item: CollBookBean) {
var top_image_view = helper.getView<ImageView>(R.id.top_image_view)
helper.setText(R.id.name_tv, item.title)
var cover = item.cover
if (cover != null) {
cover = BaseConfig.showImageUrl + cover
GlideUtil.loadAllImage(mContext,5,cover, top_image_view)
} else {
GlideUtil.loadImage(mContext, R.mipmap.read_no_cover, top_image_view)
}
}
}

页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private fun initRefreshView() {
m_refreshlayoyt.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
override fun onLoadMore(refreshLayout: RefreshLayout) {
loadmore(rorder)
}

override fun onRefresh(refreshLayout: RefreshLayout) {
refresh(rorder)
}
})
}

private fun initRecycleView() {
mListAdapter = BookAdapter(mDatas)
recycleview?.adapter = mListAdapter

recycleview?.layoutManager = GridLayoutManager(mContext, 6)

recycleview?.addItemDecoration(
RecycleViewDivider(
mContext,
LinearLayoutManager.VERTICAL,
1,
ZJColor.line
)
)

// 设置item动画
recycleview?.itemAnimator = DefaultItemAnimator()
mListAdapter?.setOnItemClickListener {
adapter, view, position ->
onItemClick(view, position)
}

mListAdapter?.animationEnable = true
recycleview?.adapter = mListAdapter
mListAdapter?.setEmptyView(R.layout.empty_bg)
}

分割线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;

import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class RecycleViewDivider extends RecyclerView.ItemDecoration {

private Paint mPaint;
private Drawable mDivider;
private int mDividerHeight = 1;//分割线高度,默认为1px
private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private boolean isShowLast = true;//是否显示最后的线

/**
* 默认分割线:高度为2px,颜色为灰色
*
* @param context
* @param orientation 列表方向
*/
public RecycleViewDivider(Context context, int orientation) {
if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("请输入正确的参数!");
}
mOrientation = orientation;

final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}

public RecycleViewDivider(Context context, int orientation, boolean isShowLast) {
this.isShowLast = isShowLast;
if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("请输入正确的参数!");
}
mOrientation = orientation;

final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}

/**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param drawableId 分割线图片
*/
public RecycleViewDivider(Context context, int orientation, int drawableId) {
this(context, orientation);
mDivider = ContextCompat.getDrawable(context, drawableId);
mDividerHeight = mDivider.getIntrinsicHeight();
if (mDividerHeight == 0) {
mDividerHeight = 1;
}
}

/**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param dividerHeight 分割线高度
* @param dividerColor 分割线颜色
*/
public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
this(context, orientation);
mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
}

/**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param dividerHeight 分割线高度
* @param dividerColor 分割线颜色
*/
public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor,boolean isShowLast) {
this(context, orientation,isShowLast);
mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
}


//获取分割线尺寸
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, mDividerHeight);
}

//绘制分割线
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}

//绘制横向 ques_item 分割线
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
final int childSize = parent.getChildCount();
int dividerCount = childSize;
if (!isShowLast) {
dividerCount = childSize - 1;
}
for (int i = 0; i < dividerCount; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + layoutParams.bottomMargin;
final int bottom = top + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}

//绘制纵向 ques_item 分割线
private void drawVertical(Canvas canvas, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
final int childSize = parent.getChildCount();
int dividerCount = childSize;
if (!isShowLast) {
dividerCount = childSize - 1;
}
for (int i = 0; i < dividerCount; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + layoutParams.rightMargin;
final int right = left + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}
}

全局上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import android.app.Application;
import android.content.Context;

public class MyApp extends Application {
private static Context context;

@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}

/**
* 获取全局上下文
*/
public static Context getContext() {
return context;
}
}

添加在manifest中

1
2
<application
android:name="MyApp" >

然后使用只要需要context但又获取不得或获取麻烦的话,只要使用:

1
MyApp.getContext()

注意

最好是在不得已的情况下使用上述方法来获取context,而不是只要用到context就使用MyApplication.getContext(),因为这涉及到View等存在生命周期的问题。