使用RecyclerView添加header上下滑动透明效果,下拉逐渐可见,上拉不可见

RvDemo8Fragment类:
package com.example.androidkotlindemo2.recyclerview.demo8

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import com.example.androidkotlindemo2.MyApp
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.bean.Item8Bean
import com.example.androidkotlindemo2.databinding.RecyclerViewDemo8MainBinding
import com.example.androidkotlindemo2.recyclerview.demo12.RV12HeaderView
import com.example.androidkotlindemo2.recyclerview.demo12.RvDemo12Fragment
import com.example.androidkotlindemo2.utils.LogUtils

/**
 * Author : wn
 * Email : maoning20080809@163.com
 * Date : 2024/6/1 10:43
 * Description : RecyclerView添加头信息上下滑动
 */
class RvDemo8Fragment : Fragment() {

    private lateinit var binding : RecyclerViewDemo8MainBinding
    private var adapter : RVDemo8Adapter? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = RecyclerViewDemo8MainBinding.inflate(inflater, container, false)
        return binding.root
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        var data = getData()
        adapter = RVDemo8Adapter(R.layout.recycler_view8_item, data)

        var linearLayoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
        binding.rvDemo8Main.let {
            it.adapter = adapter
            it.layoutManager = linearLayoutManager

            it.addOnScrollListener(object : OnScrollListener(){
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    super.onScrollStateChanged(recyclerView, newState)
                    LogUtils.i(TAG, "onScrollStateChanged newState = ${newState}")
                }

                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)

                    var scrollHeight = getScrollYDistance(recyclerView)?:1f
                    var headerHeight = adapter?.headerLayout?.height?:1f
                    if(scrollHeight != null && headerHeight != null){
                        scrollHeight = scrollHeight.toFloat()
                        headerHeight = headerHeight.toFloat()
                        //取反,模糊效果从0-1
                        var reverseHeaderHeight = headerHeight.minus(scrollHeight)
                        var heightScale = (reverseHeaderHeight) / headerHeight
                        LogUtils.i(TAG, "onScrolled dx = ${dx} , dy = ${dy} , headerHeight : ${headerHeight}, ${heightScale}")
                        //向上滚动,设置模糊效果
                        adapter?.headerLayout?.alpha = heightScale

                        if(dy < 0 && heightScale < 0){
                            if(!mIsScrollFlag){
                                mScrollHeight = scrollHeight
                                mIsScrollFlag = true
                            }
                            headerViewButtonScrollHeight = mScrollHeight - scrollHeight
                            LogUtils.e(RvDemo12Fragment.TAG, "a从上往下scrollHeight ${scrollHeight} , mScrollHeight = ${mScrollHeight} , headerViewButtonScrollHeight : ${headerViewButtonScrollHeight}")

                            //如果从上往下并且透明度小于0,显示
                            showHeaderView()
                        } else if(dy > 0 || heightScale >= 0){
                            if(mIsScrollFlag){
                                mScrollHeight = scrollHeight
                                mIsScrollFlag = false
                            }
                            //如果相等,不隐藏
                            if(scrollHeight == mScrollHeight){
                                return
                            }
                            if(binding.rvDemo8HeaderView.alpha <= 0){
                                return
                            }
                            headerViewButtonScrollHeight = headerViewButtonHeight - (scrollHeight - mScrollHeight)
                            if(headerViewButtonScrollHeight >= headerViewButtonHeight){
                                headerViewButtonScrollHeight = 0f
                            }
                            LogUtils.e(RvDemo12Fragment.TAG, "b从下往上 scrollHeight ${scrollHeight} , mScrollHeight = ${mScrollHeight} , headerViewButtonScrollHeight : ${headerViewButtonScrollHeight}")

                            //如果从下往上滑动或者透明度为大于0,隐藏
                            hideHeaderView()
                        }

                    }

                }
            })
        }


        adapter?.setOnItemClickListener { adapter, view, position ->
            LogUtils.e(TAG, "setOnItemClickListener 点击item")
        }

        initHeaderView()
    }

    private var mScrollHeight = 0f
    private var mIsScrollFlag = false

    private var headerViewButtonHeight = MyApp.myApp.resources.getDimension(R.dimen.dp_50)
    private var headerViewButtonScrollHeight = 0f


    /**
     * 显示头信息,透明度逐渐可见
     */
    private fun showHeaderView(){
        var heightScale = headerViewButtonScrollHeight / headerViewButtonHeight
        if(headerViewButtonScrollHeight > headerViewButtonHeight){
            headerViewButtonScrollHeight = headerViewButtonHeight
        }
        binding.rvDemo8HeaderView.alpha = heightScale
        binding.rvDemo8HeaderView.visibility = View.VISIBLE
        binding.rvDemo8HeaderView.showButton()
        binding.rvDemo8HeaderView.hideRecyclerView()
    }

    /**
     * 显示头信息,透明度逐渐不可见
     */
    private fun hideHeaderView(){
        var heightScale = headerViewButtonScrollHeight / headerViewButtonHeight
        if(headerViewButtonScrollHeight < 0){
            headerViewButtonScrollHeight = 0f
            binding.rvDemo8HeaderView.visibility = View.GONE
        }
        binding.rvDemo8HeaderView.alpha = heightScale
        binding.rvDemo8HeaderView.showButton()
        binding.rvDemo8HeaderView.hideRecyclerView()
    }

    private fun initHeaderView() {
        var headerView = RV8HeaderView(activity)
        adapter?.addHeaderView(headerView)
    }

    private fun getData() : MutableList<Item8Bean>{
        //1级列表
        var list = mutableListOf<Item8Bean>()
        var imgs1 = intArrayOf(R.mipmap.base_banner0, R.mipmap.base_banner1, R.mipmap.base_banner2,
            R.mipmap.base_banner3, R.mipmap.base_banner4, R.mipmap.base_banner5,
            R.mipmap.base_banner6, R.mipmap.base_banner7, R.mipmap.base_banner8, R.mipmap.base_banner9)

        repeat(3){
            for(i in imgs1.indices){
                var item8Bean = Item8Bean(i, "头信息Header:${i}", imgs1[i])
                list.add(item8Bean)
            }
        }

        return list
    }

    var headerHeight = 0

    /**
     * 有headerview获取RecyclerView滚动高度
     */
    private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            if (position == 0) {
                val headerView = layoutManager.findViewByPosition(0)
                headerHeight = headerView!!.height
            }
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return if (position == 0) {
                position * itemHeight - firstVisibleChildView.top
            } else {
                (position - 1) * itemHeight - firstVisibleChildView.top + headerHeight
            }
        }
        return null
    }


    /**
     * 没有headerview获取RecyclerView滚动高度
     */
    private fun getScrollYDistance2(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return position * itemHeight - firstVisibleChildView.top
        }
        return null
    }

    var headerHeightArray: Array<Int?>? = null

    /**
     * 有多个headerview获取RecyclerView滚动高度
     */
    private fun getScollYDistance(recyclerView: RecyclerView): Int {
        val layoutManager = recyclerView.getLayoutManager() as LinearLayoutManager
        // 获取第一个可见item的位置
        val position = layoutManager.findFirstVisibleItemPosition()
        // 获取第一个可见item
        val firstVisiableChildView = layoutManager.findViewByPosition(position)
        // 必须考虑有没有Header  预存下所有header的高度
        val headerCount: Int = adapter?.headerLayoutCount?:0
        if (headerCount > 0) {
            if (headerHeightArray == null) {
                headerHeightArray = arrayOfNulls(headerCount)
            }
            if (position < headerCount) {
                val headerView_i = layoutManager.findViewByPosition(position)
                headerHeightArray!![position] = headerView_i!!.height
            }
        }
        // 获取第一个可见item的高度
        val itemHeight = firstVisiableChildView!!.height
        // 获取第一个可见item的位置
        var distance = 0
        if (position == 0) {
            distance = position * itemHeight - firstVisiableChildView.top
        } else {
            var allHeaderHeight = 0
            for (i in 0 until Math.min(position, headerCount)) {
                allHeaderHeight = allHeaderHeight + headerHeightArray!![i]!!
            }
            distance = (position - Math.min(
                position,
                headerCount
            )) * itemHeight - firstVisiableChildView.top + allHeaderHeight
        }
        return distance
    }

    companion object {
        const val TAG = "RvDemo8Fragment"
    }


}

RVDemo8Adapter类:
package com.example.androidkotlindemo2.recyclerview.demo8

import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.bean.Item8Bean
import com.example.androidkotlindemo2.bean.ItemBean
import com.example.androidkotlindemo2.utils.LogUtils

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2024/5/25 10:35
 * Description :
 */
class RVDemo8Adapter(layoutResId : Int, data : MutableList<Item8Bean>) : BaseQuickAdapter<Item8Bean, BaseViewHolder>(layoutResId, data) {

    override fun convert(holder: BaseViewHolder, item: Item8Bean) {

        var position = holder.layoutPosition
        LogUtils.i("RVDemo8Adapter", "position : ${position}, ")
        holder.setText(R.id.rv8_item_name, item.name)
        holder.setBackgroundResource(R.id.rv8_item_img, item.imgId)

    }

}
RV8HeaderView类:
package com.example.androidkotlindemo2.recyclerview.demo8

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.Button
import android.widget.RelativeLayout
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.androidkotlindemo2.MyApp
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.bean.Item8HeaderBean
import com.example.androidkotlindemo2.utils.LogUtils

/**
 * Author : wn
 * Email : maoning20080809@163.com
 * Date : 2024/6/29 10:29
 * Description :
 */
class RV8HeaderView : RelativeLayout {

    private var btn:Button? = null

    private var recyclerView: RecyclerView? = null

    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context,attrs,defStyleAttr) {
        init()
    }

    fun init(){
        LayoutInflater.from(MyApp.myApp.baseContext).inflate(R.layout.recycler_view8_header, this, true)
        btn = findViewById(R.id.rv8_header_btn)
        btn?.setOnClickListener {
            LogUtils.i("RV8HeaderView", "点击测试按钮")
        }

        var adapter = RVDemo8HeaderAdapter(R.layout.recycler_view8_header_item, getDataList())
        recyclerView = findViewById<RecyclerView>(R.id.rv8_header_recycler_view)
        var layoutManager = GridLayoutManager(MyApp.myApp.baseContext, 2, GridLayoutManager.VERTICAL, false)
        recyclerView.let {
            it?.adapter = adapter
            it?.layoutManager = layoutManager
        }
    }


    fun showButton(){
        btn?.visibility = VISIBLE
    }

    fun hideButton(){
        btn?.visibility = GONE
    }

    fun showRecyclerView(){
        recyclerView?.visibility = VISIBLE
    }

    fun hideRecyclerView(){
        recyclerView?.visibility = GONE
    }

    private fun getDataList() : MutableList<Item8HeaderBean>{
        //1级列表
        var list = mutableListOf<Item8HeaderBean>()
        var imgs1 = intArrayOf(R.mipmap.demo_farms, R.mipmap.demo_fruits, R.mipmap.demo_pets, R.mipmap.demo_fishs)

        for(i in imgs1.indices){
            var item8Bean = Item8HeaderBean(imgs1[i])
            list.add(item8Bean)
        }
        return list
    }

}
RVDemo8HeaderAdapter类:
package com.example.androidkotlindemo2.recyclerview.demo8

import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.androidkotlindemo2.R
import com.example.androidkotlindemo2.bean.Item8Bean
import com.example.androidkotlindemo2.bean.Item8HeaderBean
import com.example.androidkotlindemo2.bean.ItemBean
import com.example.androidkotlindemo2.utils.LogUtils

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2024/5/25 10:35
 * Description :
 */
class RVDemo8HeaderAdapter(layoutResId : Int, data : MutableList<Item8HeaderBean>) : BaseQuickAdapter<Item8HeaderBean, BaseViewHolder>(layoutResId, data) {

    override fun convert(holder: BaseViewHolder, item: Item8HeaderBean) {

        var position = holder.layoutPosition
        holder.setBackgroundResource(R.id.rv8_header_item_img, item.imgId)

    }

}

Item8HeaderBean类:
package com.example.androidkotlindemo2.bean

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2023/9/24 10:12
 * Description :
 */
data class Item8HeaderBean(var imgId : Int) {

}

Item8Bean类:
package com.example.androidkotlindemo2.bean

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2023/9/24 10:12
 * Description :
 */
data class Item8Bean(var position : Int) {

    var name : String? = null
    var imgId: Int = 0

    constructor(position: Int, name: String) : this(position){
        this.name = name
    }

    constructor(position: Int, name: String, imgId: Int) : this(position){
        this.name = name
        this.imgId = imgId
    }

}

recycler_view_demo8_main.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <RelativeLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/rv_demo8_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginVertical="10dp"
            android:layout_centerHorizontal="true"
            android:textSize="16sp"
            android:textColor="@color/red"
            android:text="使用RecyclerView添加header上下滑动透明效果" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_demo8_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/rv_demo8_title" />

        <com.example.androidkotlindemo2.recyclerview.demo8.RV8HeaderView
            android:id="@+id/rv_demo8_header_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/rv_demo8_title"
            android:visibility="gone"/>

    </RelativeLayout>
</layout>

recycler_view8_item.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="@color/gray_c0c0c0"
    android:layout_marginHorizontal="20dp"
    android:layout_marginVertical="6dp"
    android:layout_height="120dp">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/rv8_item_name"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginVertical="6dp"
        android:textColor="@color/yellow"
        android:textSize="28sp"
        android:text="item" />

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/rv8_item_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/rv8_item_name"
        android:background="@mipmap/base_banner1"/>

</RelativeLayout>

recycler_view8_header.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_marginHorizontal="20dp"
    android:layout_marginVertical="6dp"
    android:layout_height="wrap_content">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv8_header_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

    <Button
        android:id="@+id/rv8_header_btn"
        android:layout_below="@+id/rv8_header_recycler_view"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginVertical="6dp"
        android:textSize="28sp"
        android:text="测试" />

</RelativeLayout>

recycler_view8_header_item.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_marginHorizontal="20dp"
    android:layout_marginVertical="6dp"
    android:layout_height="wrap_content">


    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/rv8_header_item_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/base_banner1"/>

</RelativeLayout>

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以在 RecyclerView添加头部和尾部视图来实现添加 header 和 footer 的效果。下面是一种常见的实现方式: 首先,你需要创建两个布局文件用作 header 和 footer 的视图。例如,header_view.xml 和 footer_view.xml。 然后,在你的 RecyclerView 的适配器中,你需要创建两个常量来表示 header 和 footer 的视图类型。例如,HEADER_VIEW_TYPE 和 FOOTER_VIEW_TYPE。 接下来,在适配器中,你需要重写以下几个方法: 1. getItemViewType(int position) 方法:根据 position 来返回相应的视图类型。如果 position 是 0,则返回 HEADER_VIEW_TYPE;如果 position 是数据集合的大小加上 1,则返回 FOOTER_VIEW_TYPE;否则返回普通的 item 类型。 2. onCreateViewHolder(ViewGroup parent, int viewType) 方法:根据 viewType 来创建对应的 ViewHolder。如果 viewType 是 HEADER_VIEW_TYPE 或 FOOTER_VIEW_TYPE,则使用相应的布局文件创建 ViewHolder;否则使用普通的 item 布局文件创建 ViewHolder。 3. onBindViewHolder(ViewHolder holder, int position) 方法:根据 position 来绑定数据到 ViewHolder。如果 position 是 HEADER_VIEW_TYPE 或 FOOTER_VIEW_TYPE,则不需要绑定数据;否则绑定普通的 item 数据。 最后,在你的 RecyclerView 中设置适配器,并在数据集合中添加对应的数据项作为 header 和 footer。例如,使用以下代码: ``` MyAdapter adapter = new MyAdapter(dataList); adapter.addHeader(headerData); adapter.addFooter(footerData); recyclerView.setAdapter(adapter); ``` 请注意,上述代码中的 MyAdapter 是你自定义的 RecyclerView.Adapter 子类,其中包含了添加 header 和 footer 的方法。 以上就是在 RecyclerView添加 header 和 footer 的基本步骤。希望能对你有所帮助!如有需要,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六毛六66

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值