Android疑难杂症-自定义RecyclerView的LayoutManager

  1. 1. 禁用RecyclerView手动滑动功能;
  2. 2. 示例
  3. 3. 双RecyclerView滑动绑定功能实现

禁用RecyclerView手动滑动功能;

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
public class PlanDateRecyclerView extends RecyclerView {
public PlanDateRecyclerView(Context context) {
super(context);
init();
}

public PlanDateRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}

public PlanDateRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init() {
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
}

示例

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
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
* Created by zhouzhuo810 on 2018/4/12.
*/
public class PlanCalendarLayoutManager extends RecyclerView.LayoutManager {

private int totalWidth;
private int totalHeight;
private int verticalScrollOffset;
private int horizontalScrollOffset;

private List<PlanOrderEntity> frames;
private int todayX;

public PlanCalendarLayoutManager(Context ctx, List<PlanOrderEntity> frames, int todayX) {
this.frames = frames;
this.todayX = todayX;
}

@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0 || state.isPreLayout()) {
return;
}
detachAndScrapAttachedViews(recycler);
fill(recycler, state);
}

private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) {
int itemCount = state.getItemCount();
if (itemCount <= 0) {
return;
}
if (frames != null) {
int size = Math.min(getItemCount(), frames.size());
for (int i = 0; i < size; i++) {
Rect rect = frames.get(i).getRect();
totalHeight = Math.max(rect.bottom, totalHeight);
totalWidth = Math.max(rect.right, totalWidth);
View viewForPosition = recycler.getViewForPosition(i);
if (viewForPosition instanceof ViewGroup) {
ViewGroup.LayoutParams lp = viewForPosition.getLayoutParams();
}
addView(viewForPosition);
measureChildWithMargins(viewForPosition, 0, 0);
layoutDecoratedWithMargins(viewForPosition, rect.left, rect.top, rect.right, rect.bottom);
}
totalHeight = Math.max(totalHeight, getHeight());
totalWidth = Math.max(totalWidth, getWidth());
}
}

public int getTodayX() {
return todayX - horizontalScrollOffset;
}

@Override
public boolean canScrollVertically() {
return true;
}

@Override
public boolean canScrollHorizontally() {
return true;
}

@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int travelX = dx;

//如果滑动到最左边
if (horizontalScrollOffset + dx < 0) {
travelX = -horizontalScrollOffset;
}
else if (horizontalScrollOffset + dx > totalWidth - getHorizontalSpace()) {//如果滑动到最右边
travelX = totalWidth - getHorizontalSpace() - horizontalScrollOffset;
}

//将水平方向的偏移量+travel
horizontalScrollOffset += travelX;

// 调用该方法通知view在y方向上移动指定距离
offsetChildrenHorizontal(-travelX);

return travelX;
}

public void setTotalWidth(int totalWidth) {
this.totalWidth = totalWidth;
}

@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
//列表向下滚动dy为正,列表向上滚动dy为负,这点与Android坐标系保持一致。
//实际要滑动的距离
int travel = dy;

//如果滑动到最顶部
if (verticalScrollOffset + dy < 0) {
travel = -verticalScrollOffset;
} else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//如果滑动到最底部
travel = totalHeight - getVerticalSpace() - verticalScrollOffset;
}

//将竖直方向的偏移量+travel
verticalScrollOffset += travel;

// 调用该方法通知view在y方向上移动指定距离
offsetChildrenVertical(-travel);

return travel;
}

private int getVerticalSpace() {
//计算RecyclerView的可用高度,除去上下Padding值
return getHeight() - getPaddingBottom() - getPaddingTop();
}

public int getHorizontalSpace() {
return getWidth() - getPaddingLeft() - getPaddingRight();
}

public int getTotalWidth() {
return totalWidth;
}
}

双RecyclerView滑动绑定功能实现

1
2
3
4
5
6
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
rvDate.scrollBy(dx, 0);
}
});