實現列表懸浮標籤「頂上去」的效果

NanBox發表於2017-12-13

列表頂部的標籤懸浮大家應該都知道,但「頂上去」是個啥玩意?
看一下效果圖就知道了,注意看頂部的懸浮標籤切換時的效果:

實現列表懸浮標籤「頂上去」的效果

這是我在之前一個自定義側邊索引欄的專案上修改的,對側邊索引欄的實現有興趣的可以看一下之前的文章:自定義側邊快速索引欄

思路是這樣子的:

  • 佈局裡面增加一個和索引 item 長的一樣的 view,預設顯示列表第一項的索引字母。
  • 監聽列表的滑動,當列表可見的第二項是索引 item 時,計算並更新懸浮 view 的 y 座標,讓它處於索引 item 的上方。
  • 監聽列表的滑動,當列表可見第一項發生變化時,更新懸浮 view 顯示的字母為當前可見第一項的索引字母。

感覺比想象中簡單啊。可以看出邏輯都是在滑動事件裡,我們用 RecyclerView 的 addOnScrollListener 方法監聽列表的滑動事件,在監聽器裡面實現上面的邏輯。說的可能不是很好,看程式碼就知道多簡單了。

監聽器的程式碼如下:

class mScrollListener extends RecyclerView.OnScrollListener {

    private int mFlowHeight;
    private int mCurrentPosition = -1;

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        mFlowHeight = vFlow.getMeasuredHeight();
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
        View view = layoutManager.findViewByPosition(firstVisibleItemPosition + 1);

        if (view != null) {
            if (view.getTop() <= mFlowHeight && isItem(firstVisibleItemPosition + 1)) {
                vFlow.setY(view.getTop() - mFlowHeight);
            } else {
                vFlow.setY(0);
            }
        }

        if (mCurrentPosition != firstVisibleItemPosition) {
            mCurrentPosition = firstVisibleItemPosition;
            tvFlowIndex.setText(mList.get(mCurrentPosition).getFirstWord());
        }
    }

    /**
     * @param position 對應項的下標
     * @return 是否為標籤項
     */
    private boolean isItem(int position) {
        return mAdapter.getItemViewType(position) == MainAdapter.VIEW_INDEX;
    }
}
複製程式碼

這樣就已經實現「頂上去」的效果了,妥妥的。

最後說明一下,這個程式碼是使用 RecyclerView 實現的,要是用 ListView 的話是有問題的。ListView 的 item 使用 getTop() 方法,剛開始拿到的應該是 item 距離整個 ListView 最頂部的距離,要都是這樣還好處理,但是複用 item 的時候這個值又發生了變化。
總之就是,在使用 ListView 的時候,我還沒有好的實現方法。要是哪位知道怎麼實現,希望可以留言分享一下,不勝感激!

原始碼地址

相關文章