在开发项目的时候,很多时候都需要用到上图这种功能, 章节列表。 但坑爹的是,这种控件在ios中原生自带, 但android却没有自带。这时候又不免去github里面去找一些开源库。所以说, 开发android的同学需要做各种ios的特效。
![H$RK3[L)N}]%$RX5HK)HTG.gif
github这种开源库灰常多,但开源库毕竟是别人的,能自己弄出来当然是最好的。下面我就分享下我的实现思路。
功能需求:
1.章节标题栏需要固定在顶部。
2.固定的章节标题栏可以随着列表的章节标题栏进行相应的移动。
实现:
1.固定章节栏: 采用famelayout布局, 在RecyclerView 外层添加一个章节栏标题,一直固定在顶部。
2.固定章节栏随列表章节栏移动:当判断下个进入顶部是列表章节标题的时候 ,对固定章节栏进行相应的布局调整。
主要的实现代码:
public class SectionRecyclerActivity extends AppCompatActivity {
..........
@Override
protected void onCreate(Bundle savedInstanceState) {
..........
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int position = (mLayoutManager.findFirstVisibleItemPosition() < 0) ? 0 : mLayoutManager.findFirstVisibleItemPosition();
int totalSize = mLayoutManager.getItemCount();
if (mAdapter.getItemViewType(position) == TITLE_TYPE) {
mTopTitle.setText(mDatas.get(position).content);
}
int nextPosition = position + 1;
if (nextPosition < totalSize) {
//获取下个章节标题的位置, 如果小于0说明后面没有章节标题。 如果下个章节标题位置还未显示出来,也不用做改变。
int sectionPosition = findNextSection(nextPosition, totalSize);
if (sectionPosition < 0 || sectionPosition > (position + mRecyclerView.getChildCount() - 1)) {
refreshTopTitle();
return;
}
//获取下一个章节标题的top, 如果top 大于 展示label的高度, 无须做改动。
int nextTopMargin = mLayoutManager.findViewByPosition(sectionPosition).getTop();
if (nextTopMargin < mMaxHeight) {
mTopTitleLayoutParams.topMargin = -(mMaxHeight - nextTopMargin);
mTopTitle.setLayoutParams(mTopTitleLayoutParams);
//如果当前第一个显示的不是章节标题, 需要显示上一个章节标题
if (mAdapter.getItemViewType(position) != TITLE_TYPE) {
mTopTitle.setText(findPreSectionText(position));
}
} else {
refreshTopTitle();
}
}
}
});
}
private void refreshTopTitle() {
if (mTopTitleLayoutParams.topMargin == 0) return;
mTopTitleLayoutParams.topMargin = 0;
mTopTitle.setLayoutParams(mTopTitleLayoutParams);
}
private int findNextSection(int position, int size) {
for (; position < size; position++) {
if (mAdapter.getItemViewType(position) == TITLE_TYPE) return position;
}
return -1;
}
private String findPreSectionText(int position) {
for (; position > -1; position--) {
if (mAdapter.getItemViewType(position) == TITLE_TYPE) return mDatas.get(position).content;
}
return "";
}
private boolean isInit = false;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//当activity可以获取焦点的时候,获取固定标题栏的高度
if (hasFocus && !isInit) {
isInit = true;
mMaxHeight = mTopTitle.getHeight();
}
}
..........
}
这里是主要实现逻辑的代码,主要是监听recyclerView的滚动事件对固定标题栏做相应的操作。
这里暂且只支持recylerView的垂直的线性布局。像瀑布和网格布局现在还没有支持。
完整的代码:https://github.com/hu5080126/SimpleExample/tree/master/sectionRecyclerView/src
各位同学如果还有什么更好的实现方式,欢迎留言!