android 悬浮导航

这个类`RcvStickyLayout`扩展了`FrameLayout`,用于实现RecyclerView的悬浮导航。它关联并监听RecyclerView,处理适配器数据变化,以及在滚动时更新悬浮布局的位置。当特定的Section头部到达顶部时,悬浮布局会显示该Section的标签。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

列表悬浮导航、记录~

public class RcvStickyLayout extends FrameLayout
{
    protected static final String TAG = "RcvStickyLayout";
    protected RecyclerView mRecyclerView;
    protected RecyclerView.LayoutManager mLayoutManager;
    protected ToolsItemRightDelegate.ToolsItemViewHolder mHolder;
    protected int mStickyHeight = RecyclerView.NO_POSITION;
    protected ToolItemAdapter mAdapter;
    protected int mFirstStickyPosition = RecyclerView.NO_POSITION;
    protected int mCurrentIndicatePosition = RecyclerView.NO_POSITION;
    protected List<Integer> mStickyPositionList = new LinkedList<>();
    protected int mAdapterItemCount;
    protected OnStickyLayoutClickedListener mLayoutClickedListener;

    public RcvStickyLayout(@NonNull Context context)
    {
        super(context);
        init(context, null);
    }

    public RcvStickyLayout(@NonNull Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(@NonNull Context context, @Nullable AttributeSet attrs)
    {
        setLayoutParams(new LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    }

    /**
     * 关联RecyclerView
     */
    public void attachToRecyclerView(RecyclerView recyclerView)
    {
        if (recyclerView == null)
        {
            LogUtils.i(TAG, "You must attach a recyclerView");
            return;
        }

        this.mRecyclerView = recyclerView;
        this.mLayoutManager = recyclerView.getLayoutManager();

        //检查适配器
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        if (!(adapter instanceof ToolItemAdapter))
        {
            //RcvUtils.doErrorLog(TAG, "You must set the RcvSectionSingleLabelAdapter with RecyclerView");
            return;
        }
        this.mAdapter = (ToolItemAdapter) recyclerView.getAdapter();
        resetParams();
        mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver()
        {
            @Override
            public void onChanged()
            {
                super.onChanged();
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount)
            {
                super.onItemRangeChanged(positionStart, itemCount);
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount, Object payload)
            {
                super.onItemRangeChanged(positionStart, itemCount, payload);
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }

            @Override
            public void onItemRangeInserted(int positionStart, int itemCount)
            {
                super.onItemRangeInserted(positionStart, itemCount);
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }

            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount)
            {
                super.onItemRangeRemoved(positionStart, itemCount);
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }

            @Override
            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount)
            {
                super.onItemRangeMoved(fromPosition, toPosition, itemCount);
                resetParams();
                updateScrollState(mRecyclerView.getScrollState());
            }
        });
        //初始化悬浮布局
        mHolder = mAdapter.getStickyHold(this);
        mHolder.getConvertView().setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (mLayoutClickedListener != null)
                {
                    mLayoutClickedListener.onClicked(v);
                }
            }
        });
        addView(mHolder.getConvertView(), 0);

        //添加滚动监听
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                super.onScrollStateChanged(recyclerView, newState);
                updateScrollState(newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                super.onScrolled(recyclerView, dx, dy);
                updateScrollState(recyclerView.getScrollState());
            }
        });
    }

    //更新滚动过程中的状态
    private void updateScrollState(int scrollState)
    {
        int firstVisibleP = RecyclerView.NO_POSITION;
        int firstCompleteVisibleP = RecyclerView.NO_POSITION;
        if (mLayoutManager instanceof LinearLayoutManager)
        {
            firstVisibleP = ((LinearLayoutManager) mLayoutManager).findFirstVisibleItemPosition();
            firstCompleteVisibleP = ((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
        } else if (mLayoutManager instanceof GridLayoutManager)
        {
            firstVisibleP = ((GridLayoutManager) mLayoutManager).findFirstVisibleItemPosition();
            firstCompleteVisibleP = ((GridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
        } else if (mLayoutManager instanceof StaggeredGridLayoutManager)
        {
            firstVisibleP = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(null)[0];
            firstCompleteVisibleP = ((StaggeredGridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPositions(null)[0];
        }

        //需要隐藏悬浮布局的时机
        if (mFirstStickyPosition == RecyclerView.NO_POSITION || firstVisibleP == RecyclerView.NO_POSITION
                || firstVisibleP < mFirstStickyPosition)
        {
            setVisibility(GONE);
            mCurrentIndicatePosition = RecyclerView.NO_POSITION;
            return;
        }
        setVisibility(VISIBLE);

        if (firstCompleteVisibleP == RecyclerView.NO_POSITION && firstVisibleP >= mFirstStickyPosition)
        {
            firstCompleteVisibleP = firstVisibleP;
        }
        //两个Section相顶效果
        if (mAdapter.getItems().get(firstCompleteVisibleP) instanceof ToolItemEntity)
        {
            int top = mLayoutManager.findViewByPosition(firstCompleteVisibleP).getTop();
            if (top >= 0 && top < mStickyHeight)
            {
                setY(top - mStickyHeight);
            } else
            {
                setY(0);
            }
        } else
        {
            setY(0);
        }

        if (scrollState == RecyclerView.SCROLL_STATE_IDLE || scrollState == RecyclerView.SCROLL_STATE_DRAGGING)
        {
            //停止或者手触摸拉动的情况
            updateStickyLayout(getLastSectionPosition(firstVisibleP));
        } else
        {
            //惯性滑动的情况
            if (firstVisibleP < mAdapterItemCount && firstCompleteVisibleP < mAdapterItemCount)
            {
                if (firstVisibleP > mCurrentIndicatePosition && firstVisibleP != RecyclerView.NO_POSITION
                        && mAdapter.getItems().get(firstVisibleP) instanceof ToolItemEntity)
                {
                    updateStickyLayout(firstVisibleP);
                } else if (firstVisibleP < mCurrentIndicatePosition && firstCompleteVisibleP != RecyclerView.NO_POSITION
                        && mAdapter.getItems().get(firstCompleteVisibleP) instanceof ToolItemEntity)
                {
                    updateStickyLayout(getLastStickyPosition(mCurrentIndicatePosition));
                }
            }
        }
    }

    //更新悬浮布局
    private void updateStickyLayout(int position)
    {
        if (position == RecyclerView.NO_POSITION)
        {
            return;
        }

        ToolItemEntity wrapper = (ToolItemEntity)mAdapter.getItems().get(position);
        mAdapter.onBindSectionLabelView(mHolder, wrapper);
        mCurrentIndicatePosition = position;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);
        if (mHolder != null)
        {
            mStickyHeight = mHolder.getConvertView().getHeight();
        }
    }

    //重置各参数
    private void resetParams()
    {
        mCurrentIndicatePosition = RecyclerView.NO_POSITION;
        mAdapterItemCount = mAdapter.getItemCount();

        mStickyPositionList.clear();
        if (mAdapter != null)
        {
            for (int i = 0, count = mAdapter.getItems().size(); i < count; i++)
            {
                if (mAdapter.getItems().get(i) instanceof ToolItemEntity)
                {
                    mStickyPositionList.add(i);
                }
            }
        }

        if (mStickyPositionList.size() > 0)
        {
            mFirstStickyPosition = mStickyPositionList.get(0);
        } else
        {
            mFirstStickyPosition = RecyclerView.NO_POSITION;
        }
    }

    //获取某一个Section的上一个Section的位置
    private int getLastStickyPosition(int startP)
    {
        if (mStickyPositionList == null || mStickyPositionList.size() == 0)
        {
            return RecyclerView.NO_POSITION;
        }

        int resultP = RecyclerView.NO_POSITION;
        int startIndex = mStickyPositionList.indexOf(startP);
        if (startIndex != RecyclerView.NO_POSITION && --startIndex >= 0)
        {
            resultP = mStickyPositionList.get(startIndex);
        }

        return resultP;
    }

    //获取任意位置的前一个Section的位置
    private int getLastSectionPosition(int position)
    {
        List<Integer> list = new ArrayList<>();
        list.addAll(mStickyPositionList);
        Collections.reverse(list);
        for (Integer p : list)
        {
            if (p <= position)
            {
                return p;
            }
        }
        return RecyclerView.NO_POSITION;
    }

    /**
     * 获取悬浮布局当前代表的悬浮位置
     */
    public int getCurrentIndicatePosition()
    {
        return mCurrentIndicatePosition;
    }

    /**
     * 悬浮布局点击监听
     */
    public void setOnStickyLayoutClickListener(OnStickyLayoutClickedListener listener)
    {
        this.mLayoutClickedListener = listener;
    }

    /**
     * 设置悬浮布局点击监听
     */
    public interface OnStickyLayoutClickedListener
    {
        void onClicked(View stickyLayout);
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值