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>