Android UIAndroid/Java学习日记Android开发经验谈

ListView实现粘性悬浮栏

2018-05-21  本文已影响73人  黄光华

前言

粘性悬浮栏效果,在联系人界面经常能看到,每个分组字母在滑动时能动态把上一个字母的悬浮栏顶上去。引用一张别人的动图:

Instagram的悬浮条.jpg

为了在项目中实现这种效果,我Google了下。这种效果实现的方式大概有两种:

两种方法各有优缺点。封装在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了。

上一篇下一篇

猜你喜欢

热点阅读