Android itemDecoration接口实现吸顶悬浮标题

 更新时间:2022年11月15日 16:19:44   作者:Super-B  
这篇文章主要介绍了Android中使用itemdecoration实现吸顶悬浮标题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

方案

1.设置一个悬浮的视图挂在recycleView顶部,随着item的移动位置,悬浮标题自动跟随移动或者是保持原地不动。

2.使用recyclerView的ItemDecoration,给指定的item设置不同的itemDecoration,并且跟随item的移动而移动或者保持不变。

本文采用第二种方式实现,效果图:

了解ItemDecoration

这是个接口,一共有六个方法:

public static abstract class ItemDecoration {
        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn before the item views are drawn,
         * and will thus appear underneath the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView
         */
        public void onDraw(Canvas c, RecyclerView parent, State state) {
            onDraw(c, parent);
        }
        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn after the item views are drawn
         * and will thus appear over the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView.
         */
        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            onDrawOver(c, parent);
        }
        /**
         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
         * the number of pixels that the item view should be inset by, similar to padding or margin.
         * The default implementation sets the bounds of outRect to 0 and returns.
         *
         * <p>
         * If this ItemDecoration does not affect the positioning of item views, it should set
         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
         * before returning.
         *
         * <p>
         * If you need to access Adapter for additional data, you can call
         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
         * View.
         *
         * @param outRect Rect to receive the output.
         * @param view    The child view to decorate
         * @param parent  RecyclerView this ItemDecoration is decorating
         * @param state   The current state of RecyclerView.
         */
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
        }
        /**
         * @deprecated
         * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDrawOver(Canvas c, RecyclerView parent) {
        }
        /**
         * @deprecated
         * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDraw(Canvas c, RecyclerView parent) {
        }
        /**
         * @deprecated
         * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
         */
        @Deprecated
        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
            outRect.set(0, 0, 0, 0);
        }
    }

其中有三个方法是@deprecated的,那么我们只需要看以下三个方法:

	public void onDraw(Canvas c, RecyclerView parent, State state) {
		onDraw(c, parent);
	}
	public void onDrawOver(Canvas c, RecyclerView parent, State state) {
    	onDrawOver(c, parent);
    }
	public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
		getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
	                parent);
	}

第一个方法的意思是绘制分割线本身;

第二个方法是在item项目绘制完成之后进行的绘制操作(这个会覆盖在item上面);

第三个方法是设置分割线的左间距,上间距,右间距,下间距,保存在outRect中。

如图所示:

其中最底层黄色部分大小是getItemOffsets方法返回的itemDecoration的矩阵设置边距宽度,onDraw方法根据设置的间距宽度来进行绘制黄色区域,其中棕红色部分是onDrawOver方法覆盖绘制在item上层的部分。

利用ItemDecoration来绘制悬浮标题栏

我们给每个需要title的item设置rect.top = titleHeight(标题栏高度);其他的间距可以先不考虑,不重要;

重写onDraw方法,绘制我们的itemDecoration标题栏;

我们需要重写onDrawOver方法,在滑动的时候去判断,

1)如果顶部标题区域是在该标题的items范围之内的滑动的话,那么我们需要覆盖绘制一个处于recyclerView.getpaddingTop位置的title,这样的话这个范围内滑动就有一个悬停的标题栏;

2)如果顶部的标题栏区域恰好下面紧跟着下一个标题栏,那么继续向上滑动的时候,需要下面的标题栏把上面的标题栏顶出界面之外。那么绘制的顶部标题栏的起始位置就是所处的item.bottom - titleHeight的位置。

使用以上三个步骤就可以做出一个流畅并且定制化很高的悬浮标题栏功能了。

代码

class MyDecoration(context: Context): RecyclerView.ItemDecoration() {
        var mPaint:Paint? = null
        var mPaint2:Paint? = null
        var mTextPaint:Paint? = null
        var mTitleHeight:Int? = null
        var mTitleHeight2:Int? = null
        var mTitleTextSize:Float? = null
        init {
            mTitleHeight =
                TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP,
                    30f,
                    context.getResources().getDisplayMetrics()
                ).toInt()
            mTitleHeight2 =
                TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP,
                    3f,
                    context.getResources().getDisplayMetrics()
                ).toInt()
            mTitleTextSize =
                TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_SP,
                    16f,
                    context.getResources().getDisplayMetrics()
                )
            mTextPaint = Paint()
            mTextPaint?.let {
                it.setTextSize(mTitleTextSize!!)
                it.setAntiAlias(true)
                it.setColor(Color.WHITE)
            }
            mPaint = Paint()
            mPaint?.let {
                it.setAntiAlias(true)
                it.setColor(Color.RED)
            }
            mPaint2 = Paint()
            mPaint2?.let {
                it.setAntiAlias(true)
                it.setColor(Color.BLUE)
            }
        }
        /**
         * recyclerView绘制onDraw -> item.onDraw -> onDrawOver
         */
        override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            for (index in 0 until parent.childCount) {
                val childView = parent.getChildAt(index)
                childView?.let {
                    val rect = Rect()
                    val position = parent.getChildAdapterPosition(it)
                    if (isTitleItem(position)) {
                        rect.top = childView.top - mTitleHeight!!
                        rect.bottom = childView.top
                    } else {
                        rect.top = childView.top - mTitleHeight2!!
                        rect.bottom = childView.top
                    }
                    rect.left = parent.paddingLeft
                    rect.right = parent.width - parent.paddingRight
                    if (isTitleItem(position)) {
                        mPaint?.let { it1 -> c.drawRect(rect, it1) }
                        mTextPaint?.let { it3 ->
                            c.drawText(
                                getTitleStr(position),
                                0f,
                                rect.top.toFloat() + (mTitleHeight?.div(2.00f)?:0f),
                                it3)}
                    } else {
                        mPaint2?.let { it1 -> c.drawRect(rect, it1) }
                    }
                }
            }
        }
        /**
         * recyclerView绘制onDraw -> item.onDraw -> onDrawOver
         * 绘制覆盖在item上面的分割线效果
         */
        override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            val childView = parent.getChildAt(0)
            var nextView:View? = null;
            if (1 < parent.childCount) {
                nextView = parent.getChildAt(1)
            }
            childView?.let {
                val rect = Rect()
                val position = parent.getChildAdapterPosition(it)
                mTitleHeight?.let { height ->
                    if (nextView != null
                        && it.bottom - height < parent.paddingTop
                        && isTitleItem(parent.getChildAdapterPosition(nextView))
                        && !isSameTitle(parent.getChildAdapterPosition(nextView),position)) {
                        rect.top = it.bottom - height
                        rect.bottom = it.bottom
                    } else {
                        rect.top = parent.paddingTop
                        rect.bottom = rect.top + height
                    }
                }
                rect.left = parent.paddingLeft
                rect.right = parent.width - parent.paddingRight
                mPaint?.let { it1 -> c.drawRect(rect, it1) }
                mTextPaint?.let { it3 ->
                    c.drawText(
                        getTitleStr(position),
                        0f,
                        rect.top + (mTitleHeight?.div(2.00f)?:0f),
                        it3)}
            }
        }
        /**
         * 用于设置item周围的偏移量的,类似于设置padding喝margin效果,
         * 空出的效果用于绘制分割线
         */
        override fun getItemOffsets(
            outRect: Rect,
            view: View,
            parent: RecyclerView,
            state: RecyclerView.State
        ) {
            val position:Int = parent.getChildAdapterPosition(view)
            if (position % 4 == 0) {
                outRect.top = mTitleHeight!!
            } else{
                outRect.top = mTitleHeight2!!
            }
        }
        fun isTitleItem(position: Int):Boolean {
            return position % 4 == 0
        }
        fun getTitleStr(position: Int):String {
            return "标题:${position / 4}"
        }
        fun isSameTitle(position1: Int,position2: Int):Boolean {
            return (position1 / 4) == (position2 / 4)
        }
    }

到此这篇关于Android itemDecoration接口实现吸顶悬浮标题的文章就介绍到这了,更多相关Android吸顶悬浮标题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android学习笔记45之gson解析json

    Android学习笔记45之gson解析json

    JSON即JavaScript Object Natation,是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web开发提供了一种理想的数据交换格式。通过本篇文章给大家介绍Android学习笔记45之gson解析json的相关内容,对android gson解析json相关知识感兴趣的朋友一起学习吧
    2015-12-12
  • Android使用TextInputLayout创建登陆页面

    Android使用TextInputLayout创建登陆页面

    这篇文章主要为大家详细介绍了Android使用TextInputLayout创建登陆页面,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • android开发之Json文件的读写的示例代码

    android开发之Json文件的读写的示例代码

    这篇文章主要介绍了android开发之Json文件的读写的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • Kotlin如何优雅地判断EditText数据是否为空详解

    Kotlin如何优雅地判断EditText数据是否为空详解

    这篇文章主要给大家介绍了关于Kotlin如何优雅地判断EditText数据是否为空的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用kotlin具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • Android利用Flutter path绘制粽子的示例代码

    Android利用Flutter path绘制粽子的示例代码

    端午将至,作为中华民族的非常重要的传统节日,粽子那是必不可少的。今天跟随本篇文章用Flutter path画一个会科普节日的的粽子吧
    2022-05-05
  • android listview的多列模版实例代码

    android listview的多列模版实例代码

    这篇文章主要介绍了android listview的多列模版实例代码的相关资料,这里附有实例代码,具有参考价值,需要的朋友可以参考下
    2017-01-01
  • Android Studio编写AIDL文件后如何实现自动编译生成

    Android Studio编写AIDL文件后如何实现自动编译生成

    这篇文章主要介绍了Android Studio编写AIDL文件后如何实现自动编译生成,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • Android ViewBinding使用介绍

    Android ViewBinding使用介绍

    最近这段时间在学习Kotlin,突然发现谷歌已经把kotlin-android-extensions插件废弃,目前推荐使用ViewBinding来进行替代,接下来通过本文给大家分享Android使用ViewBinding的详细步骤,感兴趣的朋友一起学习吧
    2022-09-09
  • Android OpenGL ES实现简单绿幕抠图

    Android OpenGL ES实现简单绿幕抠图

    这篇文章主要为大家介绍了Android OpenGL ES实现简单绿幕抠图示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Android控制闪光灯的方法(打开与关闭)

    Android控制闪光灯的方法(打开与关闭)

    这篇文章主要介绍了Android控制闪光灯的方法,可实现闪光灯打开与关闭的效果,涉及Android操作Camera拍照闪光灯的相关技巧,需要的朋友可以参考下
    2016-01-01

最新评论