RecycleView悬浮头部使用笔记

https://github.com/qdxxxx/StickyHeaderDecoration

1.因为头部不是我想要的,所以直接下载代码后进行修改,代码:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import java.util.HashMap;
import java.util.Map;


public abstract class RecycleViewDecoration extends RecyclerView.ItemDecoration {
    protected String TAG = "RecycleViewDecoration";
    private Paint mHeaderTxtPaint;//文字
    private Paint mHeaderContentPaint;//背景
    private Paint mBottomLinePaint;//底部线条
    private Paint mBitmapPaint;//右边箭头

    protected int headerHeight = 136;//头部高度
    private int textPaddingLeft = 30;//头部文字左边距
    private int textPaddingRght=40;//右边文字边距
    protected int bottomLineHeight=1;
    private int textSize = 50;
    private int textColor = Color.BLACK;
    private int headerContentColor = 0xffeeeeee;
    private int bottomLineColor=0xffeeeeee;
    private Bitmap bitmap;
    private int bitmapPadding=30;//箭头右边边距

    private final float txtYAxis;
    private RecyclerView mRecyclerView;


    public RecycleViewDecoration() {
        mHeaderTxtPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHeaderTxtPaint.setColor(textColor);
        mHeaderTxtPaint.setTextSize(textSize);
        mHeaderTxtPaint.setTextAlign(Paint.Align.LEFT);


        mHeaderContentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHeaderContentPaint.setColor(headerContentColor);
        Paint.FontMetrics fontMetrics = mHeaderTxtPaint.getFontMetrics();
        float total = -fontMetrics.ascent + fontMetrics.descent;
        txtYAxis = total / 2 - fontMetrics.descent;

        mBitmapPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        bitmap= BitmapFactory.decodeResource(BaseApplication.getContext().getResources(),
                R.mipmap.ic_arrow_right);

        mBottomLinePaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mBottomLinePaint.setColor(bottomLineColor);
    }
    private boolean isInitHeight = false;

    /**
     * 先调用getItemOffsets再调用onDraw
     */
    @Override
    public void getItemOffsets(Rect outRect, View itemView, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, itemView, parent, state);
        if (mRecyclerView == null) {
            mRecyclerView = parent;
        }

        if (headerDrawEvent != null && !isInitHeight) {
            View headerView = headerDrawEvent.getHeaderView(0);
            headerView
                    .measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            headerHeight = headerView.getMeasuredHeight();
            isInitHeight = true;
        }

        /*我们为每个不同头部名称的第一个item设置头部高度*/
        int pos = parent.getChildAdapterPosition(itemView); //获取当前itemView的位置
        String curHeaderName = getHeaderName(pos);         //根据pos获取要悬浮的头部名

        if (curHeaderName == null) {
            return;
        }
        if (pos == 0 || !curHeaderName.equals(getHeaderName(pos - 1))) {//如果当前位置为0,或者与上一个item头部名不同的,都腾出头部空间
            outRect.top = headerHeight;                                 //设置itemView PaddingTop的距离
        }
    }

    public abstract String getHeaderName(int pos);
    public abstract String getHeaderRightText(int pos);

    private SparseArray<Integer> stickyHeaderPosArray = new SparseArray<>();//记录每个头部和悬浮头部的坐标信息【用于点击事件】
    private GestureDetector gestureDetector;


    @Override
    public void onDrawOver(Canvas canvas, RecyclerView recyclerView, RecyclerView.State state) {
        super.onDrawOver(canvas, recyclerView, state);
        if (mRecyclerView == null) {
            mRecyclerView = recyclerView;
        }
        if (gestureDetector == null) {
            gestureDetector = new GestureDetector(recyclerView.getContext(), gestureListener);
            recyclerView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return gestureDetector.onTouchEvent(event);
                }
            });
        }

        stickyHeaderPosArray.clear();

        int childCount = recyclerView.getChildCount();//获取屏幕上可见的item数量
        int left = recyclerView.getLeft() + recyclerView.getPaddingLeft();
        int right = recyclerView.getRight() - recyclerView.getPaddingRight();

        String firstHeaderName = null;
        String headerRirhtText=null;
        int firstPos = 0;
        int translateTop = 0;//绘制悬浮头部的偏移量
        /*for循环里面绘制每个分组的头部*/
        for (int i = 0; i < childCount; i++) {
            View childView = recyclerView.getChildAt(i);
            int pos = recyclerView.getChildAdapterPosition(childView); //获取当前view在Adapter里的pos
            String curHeaderName = getHeaderName(pos);                 //根据pos获取要悬浮的头部名
            String curHeaderRightText=getHeaderRightText(pos);
            if (i == 0) {
                firstHeaderName = curHeaderName;
                headerRirhtText=curHeaderRightText;
                firstPos = pos;
            }
            if (curHeaderName == null)
                continue;//如果headerName为空,跳过此次循环

            int viewTop = childView.getTop() + recyclerView.getPaddingTop();
            if (pos == 0 || !curHeaderName.equals(getHeaderName(pos - 1))) {//如果当前位置为0,或者与上一个item头部名不同的,都腾出头部空间
                if (headerDrawEvent != null) {
                    View headerView;
                    if (headViewMap.get(pos) == null) {
                        headerView = headerDrawEvent.getHeaderView(pos);
                        headerView
                                .measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                        headerView.setDrawingCacheEnabled(true);
                        headerView.layout(0, 0, right, headerHeight);//布局layout
                        headViewMap.put(pos, headerView);
                        canvas.drawBitmap(headerView.getDrawingCache(), left, viewTop - headerHeight, null);

                    } else {
                        headerView = headViewMap.get(pos);
                        canvas.drawBitmap(headerView.getDrawingCache(), left, viewTop - headerHeight, null);
                    }
                } else {
                    canvas.drawRect(left, viewTop - headerHeight, right, viewTop, mHeaderContentPaint);
                    canvas.drawText(curHeaderName, left + textPaddingLeft, viewTop - headerHeight / 2 + txtYAxis, mHeaderTxtPaint);

                    if (!TextUtils.isEmpty(headerRirhtText)){
                        Rect mBounds = new Rect();
                        mHeaderTxtPaint.getTextBounds(headerRirhtText,0,headerRirhtText.length(),mBounds);
                        float rightTextWidth=mBounds.width();
                        canvas.drawText(headerRirhtText, right-rightTextWidth-bitmap.getWidth()-textPaddingRght, viewTop - headerHeight / 2 + txtYAxis, mHeaderTxtPaint);
                    }
                    canvas.drawBitmap(bitmap,right-bitmap.getWidth()-bitmapPadding,viewTop -headerHeight / 2 - bitmap.getHeight()/2,mBitmapPaint);
                    canvas.drawRect(left, viewTop, right, viewTop+bottomLineHeight, mBottomLinePaint);
                }
                if (headerHeight < viewTop && viewTop <= 2 * headerHeight) { //此判断是刚好2个头部碰撞,悬浮头部就要偏移
                    translateTop = viewTop - 2 * headerHeight;
                }
                stickyHeaderPosArray.put(pos, viewTop);//将头部信息放进array
                Log.i(TAG, "绘制各个头部" + pos);
            }
        }
        if (firstHeaderName == null)
            return;


        canvas.save();
        canvas.translate(0, translateTop);
        if (headerDrawEvent != null) {//inflater
            View headerView;
            if (headViewMap.get(firstPos) == null) {
                headerView = headerDrawEvent.getHeaderView(firstPos);
                headerView.measure(
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                headerView.setDrawingCacheEnabled(true);
                headerView.layout(0, 0, right, headerHeight);//布局layout
                headViewMap.put(firstPos, headerView);
                canvas.drawBitmap(headerView.getDrawingCache(), left, 0, null);
            } else {
                headerView = headViewMap.get(firstPos);
                canvas.drawBitmap(headerView.getDrawingCache(), left, 0, null);
            }
        } else {
            /*绘制悬浮的头部*/
            canvas.drawRect(left, 0, right, headerHeight, mHeaderContentPaint);
            canvas.drawText(firstHeaderName, left + textPaddingLeft, headerHeight / 2 + txtYAxis, mHeaderTxtPaint);
            if (!TextUtils.isEmpty(headerRirhtText)){
                Rect mBounds = new Rect();
                mHeaderTxtPaint.getTextBounds(headerRirhtText,0,headerRirhtText.length(),mBounds);
                float rightTextWidth=mBounds.width();
                canvas.drawText(headerRirhtText, right-rightTextWidth-bitmap.getWidth()-textPaddingRght, headerHeight / 2 + txtYAxis, mHeaderTxtPaint);
            }
            canvas.drawBitmap(bitmap,right-bitmap.getWidth()-bitmapPadding,headerHeight / 2 - bitmap.getHeight()/2,mBitmapPaint);
            canvas.drawRect(left, headerHeight, right, headerHeight+bottomLineHeight, mBottomLinePaint);
        }
        canvas.restore();

        Log.i(TAG, "绘制悬浮头部");
    }

    private Map<Integer, View> headViewMap = new HashMap<>();

    public interface OnHeaderClickListener {
        void headerClick(int pos);
    }

    private OnHeaderClickListener headerClickEvent;

    public void setOnHeaderClickListener(OnHeaderClickListener headerClickListener) {
        this.headerClickEvent = headerClickListener;
    }


    private GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            for (int i = 0; i < stickyHeaderPosArray.size(); i++) {
                int value = stickyHeaderPosArray.valueAt(i);
                LogUtil.e("value"+value);
                float y = e.getY();
                if (value - headerHeight <= y && y <= value) {//如果点击到分组头
                    if (headerClickEvent != null) {
                        headerClickEvent.headerClick(stickyHeaderPosArray.keyAt(i));
                        LogUtil.e("stickyHeaderPosArray.keyAt(i)"+stickyHeaderPosArray.keyAt(i));
                    }
                    return true;
                }
            }
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    };

    private OnDecorationHeadDraw headerDrawEvent;

    public interface OnDecorationHeadDraw {
        View getHeaderView(int pos);
    }

    /**
     * 只是用来绘制,不能做其他处理/点击事件等
     */
    public void setOnDecorationHeadDraw(OnDecorationHeadDraw decorationHeadDraw) {
        this.headerDrawEvent = decorationHeadDraw;
    }


    private Map<String, Drawable> imgDrawableMap = new HashMap<>();

    private Drawable getImg(String url) {
        return imgDrawableMap.get(url);
    }

    public void onDestory() {
        headViewMap.clear();
        imgDrawableMap.clear();
        stickyHeaderPosArray.clear();
        mRecyclerView = null;
        setOnHeaderClickListener(null);
        setOnDecorationHeadDraw(null);
    }


    public void setHeaderHeight(int headerHeight) {
        this.headerHeight = headerHeight;
    }

    public void setTextPaddingLeft(int textPaddingLeft) {
        this.textPaddingLeft = textPaddingLeft;
    }

    public void setTextSize(int textSize) {
        this.textSize = textSize;
        this.mHeaderTxtPaint.setTextSize(textSize);
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
        this.mHeaderTxtPaint.setColor(textColor);
    }

    public void setHeaderContentColor(int headerContentColor) {
        this.headerContentColor = headerContentColor;
        this.mHeaderContentPaint.setColor(headerContentColor);
    }

    public void setBottomLineHeight(int bottomLineHeight) {
        this.bottomLineHeight = bottomLineHeight;
    }

    public void setBottomLineColor(int bottomLineColor) {
        this.bottomLineColor = bottomLineColor;
        this.mBottomLinePaint.setColor(bottomLineColor);
    }
}

2.使用和原来的一样,但是滑动后头部点击没反应

https://github.com/timehop/sticky-headers-recyclerview

这个很方便,悬浮头部也可点击,但是点击返回不对,解决办法:直接判断position是否等于0,等于0就返回recycleView的当前显示的第一个item的位置,这样就可以正确获取位置了

StickyRecyclerHeadersTouchListener touchListener =
        new StickyRecyclerHeadersTouchListener(recyclerView, headersDecor);
touchListener.setOnHeaderClickListener(
        new StickyRecyclerHeadersTouchListener.OnHeaderClickListener() {
            @Override
            public void onHeaderClick(View header, int position, long headerId) {
                int itemPosition;
                if (position==0){
                    itemPosition=manager.findFirstVisibleItemPosition();
                }else {
                    itemPosition=position;
                }
    
            }
        });
recyclerView.addOnItemTouchListener(touchListener);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值