八、RecyclerView笔记


1. ScrollView嵌套 RecyclerView 滚动卡顿解决办法:

1
2
1.	use NestedScrollView instead of ScrollView
2. recyclerView.setNestedScrollingEnabled(false)

2. 分割线类 CustomDecoration 代码如下:

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
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.govnet.ui.R;

/**
* RecyclerView 分割线
*/
public class CustomDecoration extends RecyclerView.ItemDecoration {

public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

private Drawable mDivider;

private int mOrientation;

/**
* 分割线缩进值
*/
private int mInset;

private Paint mPaint;

public CustomDecoration(Context context) {
this(context, R.drawable.shape_divider_1);
}

public CustomDecoration(Context context, int drawable) {
this(context, drawable, 0);
}

public CustomDecoration(Context context, int drawable, int inset) {
this(context, VERTICAL_LIST, drawable, inset);
}

/**
* @param context
* @param orientation layout的方向
* @param drawable 引入的drawable的ID
* @param inset 分割线缩进值
*/
public CustomDecoration(Context context, int orientation, int drawable, int inset) {
mDivider = context.getResources().getDrawable(drawable);
this.mInset = inset;
mPaint = new Paint();
mPaint.setColor(context.getResources().getColor(R.color.base_white));
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
setOrientation(orientation);
}

public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}

@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}

private void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();

final int childCount = parent.getChildCount();
//最后一个item不画分割线
for (int i = 0; i < childCount - 1; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
if (mInset > 0) {
c.drawRect(left, top, right, bottom, mPaint);
mDivider.setBounds(left + mInset, top, right - mInset, bottom);
} else {
mDivider.setBounds(left, top, right, bottom);
}
mDivider.draw(c);
}
}

private void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();

final int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

/**
* 由于 Divider 也有宽高,每一个 Item 需要向下或者向右偏移
*
* @param outRect
* @param itemPosition
* @param parent
*/
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

3. 分割线类 shape_divider_1.xml 代码如下:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_divider" />
<size android:height="1dp" />
</shape>

其中颜色如下: #f2f2f2

4. RiskWarningListFragment.kt关键代码如下

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
class RiskWarningListFragment : RxLifeCycleFragment(){

private lateinit var mRiskWarningListAdapter: RiskWarningListAdapter

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_warning_list, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

mRiskWarningListAdapter = RiskWarningListAdapter(mutableListOf())
rvWarningList.run { //rvWarningList就是RecyclerView
layoutManager = LinearLayoutManager(activity)
addItemDecoration(CustomDecoration(context))
isNestedScrollingEnabled = false
}

mRiskWarningListAdapter.run {
bindToRecyclerView(rvWarningList)
setOnLoadMoreListener({
mIsRefresh = false
swipeRefreshLayout?.isRefreshing = false
mRiskWarningListReq.pageIndex = data.size / PAGE_SIZE + 1
mRiskWarningListPresenter.queryAlarmList(mRiskWarningListReq)
}, rvWarningList)

onItemClickListener = BaseQuickAdapter.OnItemClickListener { _, _, position ->

ARouter.getInstance().build(ARouterPathConstant.Warning.RISK_DETAIL_ACTIVITY)
.withInt(POSITION, position)
.withParcelable("riskDetail", getItem(position)).navigation()
}
onItemChildClickListener = BaseQuickAdapter.OnItemChildClickListener { _, view, position ->
when (view.id) {
R.id.tvDetail -> {
ARouter.getInstance().build(ARouterPathConstant.Warning.RISK_DETAIL_ACTIVITY)
.withInt(POSITION, position)
.withParcelable("riskDetail", getItem(position)).navigation()
}
R.id.tvSigning -> {
if (getItem(position)?.status == RiskWarningListAdapter.STATUS_NOT_SIGNED) {
mCurrPosition = position
mLoadingDialog = LoadingDialog(this@RiskWarningListFragment.context!!).apply {
setLoadingText(getString(R.string.in_sign_for_hint))
show()
}
val req = RiskWarningSignForReq(UserRepo.getCurrentUser()!!.account, getItem(position)!!.id, "", "1")
mSignForPresenter.signFor(req)
}
}
R.id.tvFeedBack -> {
if (getItem(position)?.status == RiskWarningListAdapter.STATUS_SIGNED_NOT_FEEDBAK) {
ARouter.getInstance().build(ARouterPathConstant.Warning.CREATE_FEEDBACK_ACTIVITY)
.withParcelable("riskDetail", getItem(position)).navigation()
}
}
}
}
}

swipeRefreshLayout?.setOnRefreshListener {
mRiskWarningListReq.pageIndex = 1
refresh()
}
}

private fun refresh() {
initReqParam()
mIsRefresh = true
mRiskWarningListAdapter.setEnableLoadMore(false)
mRiskWarningListPresenter.queryAlarmList(mRiskWarningListReq)
}

override fun onQueryWarningAlarmListSuccess(resp: RiskWarningListResp) {
resp.rows.let {
mRiskWarningListAdapter.run {
if (mIsRefresh) {
replaceData(it)
} else {
addData(it)
}
if (it.size < PAGE_SIZE || resp.total == data.size) {
loadMoreEnd(mIsRefresh)
} else {
loadMoreComplete()
}
if (mIsRefresh && mRiskWarningListReq.pageIndex < resp.pages) { // 防止不满一屏,自动调用了加载更多,导致界面上数据重复
setEnableLoadMore(true)
}
}
}
}

override fun hideLoading() {
swipeRefreshLayout?.isRefreshing = false
}
}

5. RiskWarningListAdapter.kt关键代码如下:

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
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import android.widget.TextView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.govnet.cloudeye.R


class RiskWarningListAdapter(riskWarningBean: MutableList<RiskWarningBean>): BaseQuickAdapter<RiskWarningBean, BaseViewHolder>(R.layout.item_risk_warning, riskWarningBean) {

companion object {
const val STATUS_NOT_SIGNED = "0"
const val STATUS_SIGNED_NOT_FEEDBAK = "1"
const val STATUS_ALREADY_FEEDBAK = "2"
}

override fun convert(helper: BaseViewHolder, item: RiskWarningBean) {
item.run {
helper.setText(R.id.tvRiskCategory, yjlxCn)
.setText(R.id.tvTime, cjsj)
.setText(R.id.tvRiskWarningObject, (if (TextUtils.isEmpty(name)) "" else name)
+ (if (TextUtils.isEmpty(yjdxz)) "" else "($yjdxz)"))
.setText(R.id.tvPersonType, rylbCn)
.setText(R.id.tvRiskWarningContent, gjms)
.addOnClickListener(R.id.tvDetail)
.addOnClickListener(R.id.tvSigning)
.addOnClickListener(R.id.tvFeedBack)
when (status) {
STATUS_NOT_SIGNED -> { // 未签收
helper.setVisible(R.id.tvAlreadySignFor, false)

setTextViewDrawableLeft(helper.getView(R.id.tvSigning), R.drawable.ic_sign_for_tag_nor)
helper.setText(R.id.tvSigning, mContext.getString(R.string.sign_for))
.setTextColor(R.id.tvSigning, ContextCompat.getColor(mContext, R.color.color_666666))

setTextViewDrawableLeft(helper.getView(R.id.tvFeedBack), R.drawable.ic_feedback_tag_sel)
helper.setText(R.id.tvFeedBack, mContext.getString(R.string.feedback))
.setTextColor(R.id.tvFeedBack, ContextCompat.getColor(mContext, R.color.color_cccccc))
}
STATUS_SIGNED_NOT_FEEDBAK -> { // 已签收但未反馈
helper.setVisible(R.id.tvAlreadySignFor, true)

setTextViewDrawableLeft(helper.getView(R.id.tvSigning), R.drawable.ic_sign_for_tag_sel)
helper.setText(R.id.tvSigning, mContext.getString(R.string.sign_for))
.setTextColor(R.id.tvSigning, ContextCompat.getColor(mContext, R.color.color_cccccc))

setTextViewDrawableLeft(helper.getView(R.id.tvFeedBack), R.drawable.ic_feedback_tag_nor)
helper.setText(R.id.tvFeedBack, mContext.getString(R.string.feedback))
.setTextColor(R.id.tvFeedBack, ContextCompat.getColor(mContext, R.color.color_666666))

}
else -> { // 已反馈
helper.setVisible(R.id.tvAlreadySignFor, true)

setTextViewDrawableLeft(helper.getView(R.id.tvSigning), R.drawable.ic_sign_for_tag_sel)
helper.setText(R.id.tvSigning, mContext.getString(R.string.sign_for))
.setTextColor(R.id.tvSigning, ContextCompat.getColor(mContext, R.color.color_cccccc))

setTextViewDrawableLeft(helper.getView(R.id.tvFeedBack), R.drawable.ic_feedback_tag_sel)
helper.setText(R.id.tvFeedBack, mContext.getString(R.string.already_feedback))
.setTextColor(R.id.tvFeedBack, ContextCompat.getColor(mContext, R.color.color_cccccc))
}
}
}
}

private fun setTextViewDrawableLeft(textView: TextView, drawableLeftResId: Int) {
textView.setCompoundDrawables(ContextCompat.getDrawable(mContext, drawableLeftResId)?.apply {
setBounds(0, 0, minimumWidth, minimumHeight)
}, null, null, null)
}
}

6. fragment_warning_list.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/layout_full"
android:orientation="vertical">

<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
style="@style/layout_full"
android:background="@color/color_white">

<android.support.v7.widget.RecyclerView
android:id="@+id/rvWarningList"
style="@style/layout_full"
android:scrollbars="vertical" />

</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>

这里的 SwipeRefreshLayout 用于下拉刷新上拉加载