ListView实现粘性悬浮栏
2018-05-21 本文已影响73人
黄光华
前言
粘性悬浮栏效果,在联系人界面经常能看到,每个分组字母在滑动时能动态把上一个字母的悬浮栏顶上去。引用一张别人的动图:
Instagram的悬浮条.jpg为了在项目中实现这种效果,我Google了下。这种效果实现的方式大概有两种:
- 封装在ListView中,要重写onDraw()等方法
- 在ListView的父布局的顶部增加一个View作为悬浮栏,通过监听列表滑动动态设置悬浮栏的显隐和偏移量。
两种方法各有优缺点。封装在ListView的方法封装性较好,但是处理逻辑复杂,对技术要求比较高。第二种方法封装得不太好,每次想将该效果移植到另一个页面,要复制好几处代码,但是移植时核心逻辑是不需要重新写的,只需要替换一下变量名。
我用了第二种方法,参考的是一篇简书上的文章Android轻松实现RecyclerView悬浮条
,不过他用的是RecyclerView,其实核心逻辑不用变,直接拿过来用就可以了,只是因为监听API的不同而需要稍作改装就可以了。
思路分析
RecyclerView中的核心逻辑是这样
mFeedList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
mSuspensionHeight = mSuspensionBar.getHeight();
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//我们只是简单的收窄了我们让悬浮条移动的条件,这里就是ItemType必须对应时才发生移动
if (adapter.getItemViewType(mCurrentPosition + 1) == MultiFeedAdapter.TYPE_TIME) {
View view = linearLayoutManager.findViewByPosition(mCurrentPosition + 1);
if (view != null) {
if (view.getTop() <= mSuspensionHeight) {
mSuspensionBar.setY(-(mSuspensionHeight - view.getTop()));
} else {
mSuspensionBar.setY(0);
}
}
}
if (mCurrentPosition != linearLayoutManager.findFirstVisibleItemPosition()) {
mCurrentPosition = linearLayoutManager.findFirstVisibleItemPosition();
mSuspensionBar.setY(0);
updateSuspensionBar();
}
}
});
作者:_Nightmare
链接:https://www.jianshu.com/p/fe69a53502ab
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
然而ListView并没有LayoutManager来让我们调用findViewByPosition(),于是我用了另一个方法View itemView = mListView.getChildAt(1),来获取正在将当期悬浮栏顶上去的那个itemView。
具体的ListView监听代码如下(我考虑了添加headerView的情况)
int mHeaderCount = 2;//项目中添加到ListView的headerView的数量
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//如果还没滚出headerView范围内,不需要显示悬浮栏
if (firstVisibleItem < mHeaderCount || mCommentAdapter.getDataList().size() == 0) {
mSuspensionBarLayout.setVisibility(View.GONE);
} else {
mSuspensionBarLayout.setVisibility(View.VISIBLE);
}
//如果还没显示悬浮栏,就不需要下一步处理了
if (mSuspensionBarLayout.getVisibility() != View.VISIBLE) {
return;
}
mSuspensionHeight = mSuspensionBar.getHeight();
if (mCommentAdapter.getItemViewType((firstVisibleItem - mHeaderCount) + 1) == NewsArticleCommentAdapter.TYPE_TITLE) {// 要 + 1 是因为,要预测下一个即将顶上来的item是不是目标类型
View itemView = mListView.getChildAt(1);
if (itemView != null) {
if (itemView.getTop() <= mSuspensionHeight) {
mSuspensionBar.setTranslationY(-(mSuspensionHeight - itemView.getTop()));
} else {
mSuspensionBar.setTranslationY(0);
}
}
}
if (mCurrentPosition != firstVisibleItem) {
mCurrentPosition = firstVisibleItem;
mSuspensionBar.setTranslationY(0);
updateSuspensionBar(mCommentAdapter.getItem((firstVisibleItem - mHeaderCount)));
}
}
});
好了,这就是ListView的核心逻辑。demo可以参考Android轻松实现RecyclerView悬浮条
里面的,因为核心逻辑是一样的,布局什么的也一样,只是上面提到的scrollListener的API有点不同,我就不另外写demo了。