FormLayoutManager首页,里面有github地址
目录
前言
表格基本实现了,但表格顶部通常有个标题的横线列表跟着一起水平滚动,或是左侧有个垂直列表的标题跟着一起垂直滚动。有一个联合滚动的工具类FormScrollHelper在我封装的库里面,接下来就是要解说FormScrollHelper这个类。
FormScrollHelper代码
要用FormScrollHelper这个帮助类,前提是你的标题的列表必须也是用RecyclerView。代码只有几十行,用法可以参考demo的HFormActivity,VFormActivity和HVFormActivity。
FormScrollHelper formScrollHelper = new FormScrollHelper();
formScrollHelper.connectRecyclerView(mRecyclerView);
formScrollHelper.connectRecyclerView(rvTopTitle);
formScrollHelper.connectRecyclerView(rvLeftTitle);
上面的代码是HVFormActivity的代码,其实就是把几个RecyclerView都放进connectRecyclerView方法即可。而这个方法主要就是让RecyclerView设置一个mScrollListener,和把所有RecyclerView加到FormScrollHelper管理的一个列表里,所以我们主要还是看一下这个mScrollListener。
private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
// 以下场景处理的是,滑动过程中手指松开,移到另外一个recyclerview进行滚动
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
// 该recyclerview进入滚动状态的时候,其余四个要先停止滚动
int currentIndex = mRecyclerViews.indexOf(recyclerView);
for (int i = 0; i < mRecyclerViews.size(); i++) {
if (i != currentIndex) {
mRecyclerViews.get(i).stopScroll();
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
// 手指所放在的当前recyclerview的下标
int currentIndex = mRecyclerViews.indexOf(recyclerView);
for (int i = 0; i < mRecyclerViews.size(); i++) {
if (i != currentIndex) {
mRecyclerViews.get(i).scrollBy(dx, dy);
}
}
}
}
};
先看onScrolled方法,这个方法里面拿到的recyclerView就是手指正在操作的列表,然后根据列表拿到该RecyclerView的下标。接着遍历列表让其他RecyclerView滚动相同的dx和dy,就OK了。
再看onScrollStateChanged,相信大家也猜到是干什么的了(因为有注释)。没错,就是当你滑动一个列表,手指松开的一刻,那个列表其实还会有一段滑动的fling距离。这时你的手指松开并且是移到另外一个列表进行滑动的时候,必须手指不触摸的所有RecyclerView停下来。要是它们不停下来,你同时又在滑动新触摸的那个列表时,表格跟标题列表就会错位。其实代码也很简单,就是拿到新触摸的RecyclerView下标,然后遍历RecyclerView列表让其他RecyclerView调用stopScroll停下来。
然后就说完了,就是这样,就可以实现几个RecyclerView的联合滚动。
TFormScrollHelper代码
这个帮助类是干什么的呢?可以看看demo的TFormActivity界面,如果你的业务跟金融期权有关,你可能了解到,有一种东西叫T型表。如下图的一个表:
但是这个帮助类,我没有封装在库里面,而是写在demo里面供大家参考一下。正所谓各花各眼,这个帮助类未必能符合你的需求,所以只给大家参考一下实现联动的思路方法。从TFormActivity可以看到用法如下:
// 设置RecyclerView联动
TFormScrollHelper scrollHelper = new TFormScrollHelper();
scrollHelper.connectRecyclerView(rvLeftTitle, TFormScrollHelper.LEFT_AREA);
scrollHelper.connectRecyclerView(rvLeftForm, TFormScrollHelper.LEFT_AREA);
scrollHelper.connectRecyclerView(rvNum, TFormScrollHelper.CENTER_AREA);
scrollHelper.connectRecyclerView(rvRightTitle, TFormScrollHelper.RIGHT_AREA);
scrollHelper.connectRecyclerView(rvRightForm, TFormScrollHelper.RIGHT_AREA);
调用connectRecyclerView关联RecyclerView的同时,传入一个区域值,这个区域值只分为左中右。
public void connectRecyclerView(RecyclerView recyclerView, int areaType){
recyclerView.addOnScrollListener(mScrollListener);
mViewIntegerMap.put(recyclerView, areaType);
}
这次用一个map来保存所有的RecyclerView,而且是那RecyclerView来当key的。接下来也是看一下mScrollListener的代码。
private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
// 以下场景处理的是,滑动过程中手指松开,移到另外一个recyclerview进行滚动
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
// 该recyclerview进入滚动状态的时候,其余四个要先停止滚动
for (RecyclerView view : mViewIntegerMap.keySet()){
if (view != recyclerView){
view.stopScroll();
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
// 当前手指操作的区域
int currentArea = mViewIntegerMap.get(recyclerView);
for (RecyclerView view : mViewIntegerMap.keySet()){
if (view != recyclerView){
int areaType = mViewIntegerMap.get(view);
view.scrollBy(areaType == currentArea ? dx : -dx, dy);
}
}
}
}
};
看了上面那张演示图,可以发现垂直滚动是同方向一起滚的,但左右区域的列表水平的滚动方向是相反的。我们来看一下onScrolled的方法。先把当前操作的RecyclerView所在的区域currentArea拿到,然后也是遍历所有RecyclerView,除了正在触摸的RecyclerView以外其他RecyclerView都要调用scrollBy,重点是与之前不同的是,要调用scrollBy的那个RecyclerView如果与当前触摸区域不同的,传入的参数是 -dx。有人也许会有疑问,我在触摸左区域的列表,而中间区域的序号列表跟当前区域也不同啊,那它不就接收 -dx的滚动距离了吗。没错是的,不过中间那个列表只能垂直滚动,所以水平距离,我们传什么值都不会有影响。
而onScrollStateChanged里面的原理跟上一个帮助类说的一样,这里就不多说了。