1. 程式人生 > >Android 懸浮頭部什麼的

Android 懸浮頭部什麼的

https://github.com/zhangqifan1/Demo_ok3

這個效果我想了很久,一如既往的去搜了搜,然後讓我逮到一個關鍵字  , 懸浮

然後又搜了搜 Suspension 最後貨比幾家  這個實現最合理

有多條目的 有ItemDecoration的

我找的這個是結合的  ,然後我又結合了BaseRecyclerViewHolderAdapter

 

1.寫個多條目

這個就不佔了

2.注意我這個是結合BaseRecyclerViewHolderAdapter的 你稍微改一下就行了

public class StickyItemDecoration extends RecyclerView.ItemDecoration{
    /**
     * Adapter :託管資料集合,為每個子項建立檢視
     */
    private MultiAdapter mAdapter;
    /**
     * 標記:UI滾動過程中是否找到標題
     */
    private boolean mCurrentUIFindStickView;
    /**
     * 標題距離頂部距離
     */
    private int mStickyItemViewMarginTop;
    /**
     * 標題佈局高度
     */
    private int mItemViewHeight;
    /**
     * 標題的檢視View
     */
    private View mStickyItemView;
    /**
     * 承載子項檢視的holder
     */
    private RecyclerView.ViewHolder mViewHolder;
    /**
     * 子項佈局管理
     */
    private LinearLayoutManager mLayoutManager;
    /**
     * 繫結資料的position
     */
    private int mBindDataPosition = -1;

    /**
     * 所有標題的position list
     */
    private List<Integer> mStickyPositionList = new ArrayList<>();

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        if (parent.getAdapter().getItemCount() <= 0) return; //非空判斷
        mCurrentUIFindStickView = false;//標記預設不存在小標題
        mLayoutManager = (LinearLayoutManager) parent.getLayoutManager();//獲取佈局管理方式

        for (int i =0 ,size = parent.getChildCount() ; i < size ; i++){//viewgroup.getChildCount():獲取所有可見子元素個數。

            View item = parent.getChildAt(i); //迴圈得到每一個子項

            if ((boolean)item.getTag() ){//判斷第幾個子項是標題(值在Adapter中設定)
                mCurrentUIFindStickView =true;//標記為true
                getStickyViewHolder(parent);//得到標題的 viewHolder
                cacheStickyViewPosition(i); //收集標題的 position

                if (item.getTop() <= 0) {//標題和父佈局的距離。(一般初始化時候先進入)
                    bindDataForStickyView(mLayoutManager.findFirstVisibleItemPosition(), parent.getMeasuredWidth());//將第一個可見子項位置 和 父佈局寬 傳入
                } else {
                    if (mStickyPositionList.size() > 0) {
                        if (mStickyPositionList.size() == 1) {//若只快取一個標題
                            bindDataForStickyView(mStickyPositionList.get(0), parent.getMeasuredWidth());
                        } else {
                            int currentPosition = mLayoutManager.findFirstVisibleItemPosition() + i;//得到標題在RecyclerView中的position
                            int indexOfCurrentPosition = mStickyPositionList.lastIndexOf(currentPosition);//根據標題的position獲得所在快取列表中的索引
                            bindDataForStickyView(mStickyPositionList.get(indexOfCurrentPosition - 1), parent.getMeasuredWidth());
                        }
                    }
                }

                if (item.getTop() > 0 && item.getTop() <= mItemViewHeight) {//處理兩個標題疊在一起的繪製效果
                    mStickyItemViewMarginTop = mItemViewHeight - item.getTop();
                } else {
                    mStickyItemViewMarginTop = 0;
                    View nextStickyView = getNextStickyView(parent);//得到下一個標題view
                    if (nextStickyView != null && nextStickyView.getTop() <= mItemViewHeight) {//若兩標題疊在一起了
                        mStickyItemViewMarginTop = mItemViewHeight - nextStickyView.getTop();//第二個標題蓋住第一個標題多少了
                    }
                }

                drawStickyItemView(c);// 準備工作已就緒,開始畫出吸附的標題

                break;  //結束迴圈
            }
        }

        if (!mCurrentUIFindStickView) {//取反判斷(因為它預設值是false)表示:若存在小標題則進入
            mStickyItemViewMarginTop = 0;
            //判斷子元素等於item總數並且快取數大於0
            if (mLayoutManager.findFirstVisibleItemPosition() + parent.getChildCount() == parent.getAdapter().getItemCount() && mStickyPositionList.size() > 0) {
                bindDataForStickyView(mStickyPositionList.get(mStickyPositionList.size() - 1), parent.getMeasuredWidth());
            }
            drawStickyItemView(c);//繪製圖層
        }

    }
    /**
     * 得到下一個標題
     * @param parent
     * @return
     */
    private View getNextStickyView(RecyclerView parent) {
        int num = 0;
        View nextStickyView = null;
        for (int m = 0, size = parent.getChildCount(); m < size; m++) {
            View view = parent.getChildAt(m);//迴圈獲取每個子項
            if ((boolean)view.getTag()) {//拿到標題
                nextStickyView = view;
                num++;
            }
            if (num == 2) break;//拿到第二個標題 ,就結束迴圈。
        }
        return nextStickyView;
    }
    /**
     * 得到標題的 viewHolder
     * @param recyclerView
     */
    private void getStickyViewHolder(RecyclerView recyclerView) {
        if (mAdapter != null) return; //判斷是否已建立
        mAdapter = (MultiAdapter) recyclerView.getAdapter();
        mViewHolder = mAdapter.onCreateDefViewHolder(recyclerView, AdapterBean.TYPE1); //該方法屬於Adapter中的重寫Override

        mStickyItemView = mViewHolder.itemView;//得到佈局
    }

    /**
     *  收集標題的 position
     * @param i
     */
    private void cacheStickyViewPosition(int i) {
        int position = mLayoutManager.findFirstVisibleItemPosition() + i;//得到標題在RecyclerView中的position
        if (!mStickyPositionList.contains(position)) {//防止重複
            mStickyPositionList.add(position);
        }
    }

    /**
     * 給StickyView繫結資料
     * @param position
     */
    private void bindDataForStickyView(int position, int width) {
        if (mBindDataPosition == position || mViewHolder == null) return;//已經是吸附位置了 或 檢視不存在
        mBindDataPosition = position;
        mAdapter.onBindViewHolder((BaseViewHolder) mViewHolder, mBindDataPosition);//改變標題的展示效果,該方法在Adapter中
        measureLayoutStickyItemView(width);//設定佈局位置及大小
        mItemViewHeight = mViewHolder.itemView.getBottom() - mViewHolder.itemView.getTop();//計算標題佈局高度
    }
    /**
     * 設定佈局位置及大小
     * @param parentWidth  父佈局寬度
     */
    private void measureLayoutStickyItemView(int parentWidth) {
        if (mStickyItemView == null || !mStickyItemView.isLayoutRequested()) return;

        int widthSpec = View.MeasureSpec.makeMeasureSpec(parentWidth, View.MeasureSpec.EXACTLY);
        int heightSpec;

        ViewGroup.LayoutParams layoutParams = mStickyItemView.getLayoutParams();
        if (layoutParams != null && layoutParams.height > 0) {
            heightSpec = View.MeasureSpec.makeMeasureSpec(layoutParams.height, View.MeasureSpec.EXACTLY);
        } else {
            heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        }

        mStickyItemView.measure(widthSpec, heightSpec);
        /**
         * view.layout(l,t,r,b) ; 子佈局相對於父佈局的繪製的位置及大小。
         * l 和 t 是控制元件左邊緣和上邊緣相對於父類控制元件左邊緣和上邊緣的距離。r 和 b是控制元件右邊緣和下邊緣相對於父類控制元件左邊緣和上邊緣的距離。
         */
        mStickyItemView.layout(0, 0, mStickyItemView.getMeasuredWidth(), mStickyItemView.getMeasuredHeight());
    }

    /**
     * 繪製標題
     * @param canvas
     */
    private void drawStickyItemView(Canvas canvas) {
        if (mStickyItemView == null) return;

        int saveCount = canvas.save();//儲存當前圖層
        canvas.translate(0, -mStickyItemViewMarginTop);//圖層轉換位移
        mStickyItemView.draw(canvas);
        canvas.restoreToCount(saveCount); //恢復指定層的圖層
    }
}

 

recyclerview.additemdecoration~