仿小米通訊錄 右側滑動條與帶動畫的懸停列表實現(二)

效果圖

這裏寫圖片描述

爲了能一眼看出如何實現 看下圖

這裏寫圖片描述

上面的title就是用到了一個RecyclerView.ItemDecoration

從字面上翻譯他就是一個recyclerview item 的裝飾

如何使用?

自定義一個類(IndicatorDecoration )繼承 RecyclerView.ItemDecoration

IndicatorDecoration extends RecyclerView.ItemDecoration 

構造方法進行一些初始化 別忘了傳入 Context

public IndicatorDecoration(Context ctx, List<? extends ContactsBean> data) {
        super();
        mContext = ctx;
        mData = data;

        final TypedArray a = mContext.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();

        mTitleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, ctx
                .getResources().getDisplayMetrics());
        mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, ctx
                .getResources().getDisplayMetrics());
        //抗鋸齒
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setTextSize(mTextSize);
    }

設置item的邊框 其實就是設置個左上右下的邊距 給要Draw的東西留下位置

//設置item周圍邊框的補償
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State
            state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        if (position == 0) {
            outRect.set(0, mTitleHeight, 0, 0);//左上右下
        } else if (mData.get(position).index != null && mData.get(position).index != mData.get
                (position - 1).index) {
            //如果當前條目的index 也就是 拼音首字母 和上一個條目不同 則有title
            outRect.set(0, mTitleHeight, 0, 0);
        } else {
            outRect.set(0, 0, 0, 0);
        }
    }

開始畫

RecyclerView的draw方法中會先通過super.draw()調用父類也就是View的draw方法,進而繼續調用RecyclerView的OnDraw方法,ItemDecorations的onDraw方法就在此時會被調用

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {

        int left;
        int top;
        int right;
        int bottom;

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams childParams = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            int position = childParams.getViewLayoutPosition();

            left = parent.getPaddingLeft();
            top = child.getTop() - childParams.topMargin - mTitleHeight;
            right = parent.getWidth() - parent.getPaddingRight();
            bottom = top + mTitleHeight;

            if (position == 0) {

                drawTitle(c, left, top, right, bottom, child, childParams, position);
            } else if (mData.get(position).index != null && !mData.get(position).index .equals(mData.get
                    (position - 1).index) ) {

                drawTitle(c, left, top, right, bottom, child, childParams, position);
            }
        }
    }
private void drawTitle(Canvas c, int left, int top, int right, int bottom, View child,
                           RecyclerView.LayoutParams
                                   params, int position) {

        mPaint.setColor(mContext.getResources().getColor(R.color.md_blue_300));
        c.drawRect(left, top, right, bottom, mPaint);
        mPaint.setColor(mContext.getResources().getColor(R.color.md_white_1000));

        float textHeight = getTextHeight(mData.get(position).name);

        // 將字母繪製到 title的中間
        c.drawText(mData.get(position).index, child.getPaddingLeft(), child.getTop() - params
                .topMargin - mTitleHeight / 2 + textHeight / 2, mPaint);

    }

返回文字的高

 /**
     * @param text
     * @return 返回文字的高
     */
    private float getTextHeight(String text) {
        Rect rect = new Rect();
        mPaint.getTextBounds(text, 0, text.length(), rect);
        return rect.height();
    }

動畫效果實現 onDrawOver在OnDraw 方法結束後調用

當處於這種臨界值 child.getTop() + child.getHeight() = mTitleHeight
下一步 上面的title將要上移 (注:getTop此時爲負)
所以就將 canvas上移。
這裏寫圖片描述

    @Override
 public void onDrawOver(Canvas c, final RecyclerView parent, RecyclerView.State state) {
        int firstPos = ((LinearLayoutManager) parent.getLayoutManager())
                .findFirstVisibleItemPosition();

        View child = parent.findViewHolderForAdapterPosition(firstPos).itemView;
        //canvas是否移動過的
        boolean flag = false;
        if (!mData.get(firstPos).index.equals(mData.get(firstPos + 1 ).index)) {
            if (child.getTop() + child.getHeight() < mTitleHeight) {
                //在canvas 移動前先保存他的狀態
                c.save();
                flag = true;
                c.translate(0, child.getTop() + child.getHeight() - mTitleHeight);
            }

        }

        //mPaint.setColor(mContext.getResources().getColor(R.color.md_blue_300));
        mPaint.setColor(mContext.getResources().getColor(R.color.md_amber_900));


        c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getRight() - parent
                .getPaddingRight(), parent.getPaddingTop() + mTitleHeight, mPaint);
        mPaint.setColor(mContext.getResources().getColor(R.color.md_white_1000));

        float textHeight = getTextHeight(mData.get(firstPos).name);

        // 將字母繪製到 title的中間
        c.drawText(mData.get(firstPos).index, child.getPaddingLeft(), mTitleHeight - mTitleHeight
                / 2 + textHeight / 2, mPaint);

        //如果canvas 移動過 回到他保存前的狀態
        if(flag){
            c.restore();
        }

    }

github:https://github.com/REIGE/AddressBook

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章