Android kotlin自定义RecyclerView实现横竖滚动功能

目录

1.概述

 2.kotlin自定义RecyclerView实现横竖滚动功能的功能分析和实现步骤

  2.1 自定义RecyclerView实现横竖滚动功能分析

 2.2 自定义RecyclerView实现横竖滚动功能实现

  2.2.1 自定义数据实现类

2.2.2 自定义子条目RecyclerView的适配器

2.2.3 自定义子条目右边部分滚动的适配器

2.2.4 头部适配器数据的定义

2.2.5 Acvitiy中实现数据的绑定和调用

2.2.6 xml布局文件


1.概述

  在kotlin实现app的开发中,在使用RecyclerView来实现列表功能,但是原生的api不支持横竖屏通过滚动功能,所以需要自定义RecyclerView来实现这个功能,这就需要横竖屏一个RecyclerView来实现功能,同时解决滚动冲突的问题

如图:

 2.kotlin自定义RecyclerView实现横竖滚动功能的功能分析和实现步骤

  2.1 自定义RecyclerView实现横竖滚动功能分析

    自定义RecyclerView实现横竖滚动功能实现,首选需要一个头部RecyclerView,然后在有一个
子条目RecyclerView,头部RecyclerView滚动的时候或者子条目横向滚动的时候实现联动功能
同时需要处理滚动的冲突,来实现既可以横屏滚动又可以竖屏滚动的功能

 2.2 自定义RecyclerView实现横竖滚动功能实现

  2.2.1 自定义数据实现类


  自定义RecyclerView实现横竖滚动功能

package com.proj.linkage

import java.util.*

/**
 * 数据类
 */
class DataEntity {
    var leftTitle: String? = null
        get() = if (field == null) "" else field
    var rightDatas: List<String>? = null
        get() = if (field == null) {
            ArrayList()
        } else field

}

数据类实现对数据的封装,然后在RecyclerView的横竖屏功能中调用数据实现功能

2.2.2 自定义子条目RecyclerView的适配器

  package com.proj.linkage

import android.content.Context
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.proj.linkage.ContentAdapter.ItemViewHolder
import java.util.*

class ContentAdapter(private val context: Context, headRecycler: RecyclerView) : RecyclerView.Adapter<ItemViewHolder>() {
    private var datas: List<DataEntity>? = null
    private val observerList = HashSet<RecyclerView>()
    private var firstPos = -1
    private var firstOffset = -1
    fun setDatas(datas: List<DataEntity>?) {
        this.datas = datas
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ItemViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.layout_item_content, viewGroup, false)
        return ItemViewHolder(view)
    }

    override fun onBindViewHolder(itemViewHolder: ItemViewHolder, i: Int) {
        //itemViewHolder.tvLeftTitle.setText(datas.get(i).getLeftTitle());
        val linearLayoutManager = LinearLayoutManager(context)
        linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
        itemViewHolder.rvItemRight.layoutManager = linearLayoutManager
        itemViewHolder.rvItemRight.setHasFixedSize(true)
        val rightScrollAdapter = RightScrollAdapter(context)
        rightScrollAdapter.setDatas(datas!![i].rightDatas)
        itemViewHolder.rvItemRight.adapter = rightScrollAdapter

        initRecyclerView(itemViewHolder.rvItemRight)
    }

    override fun getItemCount(): Int {
        return if (null == datas) 0 else datas!!.size
    }

    inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var rvItemRight: RecyclerView

        init {
            rvItemRight = itemView.findViewById(R.id.rv_item_right)
        }
    }

    fun initRecyclerView(recyclerView: RecyclerView) {
        recyclerView.setHasFixedSize(true)
        //为每一个recycleview创建layoutManager
        val layoutManager = recyclerView.layoutManager as LinearLayoutManager?
        //todo
        // 通过移动layoutManager来实现列表滑动  此行是让新加载的item条目保持跟已经滑动的recycleview位置保持一致
        // 也就是上拉加载更多的时候  保证新加载出来的item 跟已经滑动的item位置保持一致
        if (layoutManager != null && firstPos > 0 && firstOffset > 0) {
            layoutManager.scrollToPositionWithOffset(firstPos + 1, firstOffset)
        }
        // 添加所有的 recyclerView
        observerList.add(recyclerView)
        //当触摸条目的时候 停止滑动
        recyclerView.setOnTouchListener { view, motionEvent ->
            when (motionEvent.action) {
                MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> for (rv in observerList) {
                    rv.stopScroll()
                }
            }
            false
        }
        //添加当前滑动recycleview的滑动监听事件
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val linearLayoutManager = recyclerView.layoutManager as LinearLayoutManager?
                //获取第一个item的位置
                val firstPos1 = linearLayoutManager!!.findFirstVisibleItemPosition()
                val firstVisibleItem = linearLayoutManager.getChildAt(0)
                if (firstVisibleItem != null) {
                    //获取item的偏移量
                    val firstRight = linearLayoutManager.getDecoratedRight(firstVisibleItem)
                    for (rv in observerList) {
                        if (recyclerView !== rv) {
                            val layoutManager = rv.layoutManager as LinearLayoutManager?
                            if (layoutManager != null) {
                                firstPos = firstPos1
                                firstOffset = firstRight
                                //通过设置当前item的位置和偏移量的位置来更新recycleview 同步其它item的移动距离
                                layoutManager.scrollToPositionWithOffset(firstPos + 1, firstRight)
                            }
                        }
                    }
                }
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
            }
        })
    }

    init {
        initRecyclerView(headRecycler)
    }
}

通过上述ContentAdapter的代码可以看出这个类很重要,在initRecyclerView中设置子条目recyclerview和头部recyclerview的联动监听头部recyclerView的滑动,然后也开始滑动
并且滑动距离也是需要一样的,保持头部数据和子条目数据的一致,在代码中做了详细的分析

2.2.3 自定义子条目右边部分滚动的适配器

package com.proj.linkage

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.proj.linkage.ItemScrollAdapter.ScrollViewHolder

class ItemScrollAdapter(private val context: Context) : RecyclerView.Adapter<ScrollViewHolder>() {
    private var rightDatas: List<String>? = null
    fun setDatas(rightDatas: List<String>?) {
        this.rightDatas = rightDatas
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ScrollViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.layout_item_scroll, viewGroup, false)
        return ScrollViewHolder(view)
    }

    override fun onBindViewHolder(scrollViewHolder: ScrollViewHolder, i: Int) {
        scrollViewHolder.mTvScrollItem.text = rightDatas!![i]
    }

    override fun getItemCount(): Int {
        return if (null == rightDatas) 0 else rightDatas!!.size
    }

    inner class ScrollViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var mTvScrollItem: TextView

        init {
            mTvScrollItem = itemView.findViewById(R.id.tv_right_scroll)
        }
    }

}

在上述的ItemScrollAdapter 中的相关代码,主要处理子条目右边滑动的时候的数据绑定和同步显示更新的布局绑定
通过在ContentAdapter的适配器中同步滚动数据

2.2.4 头部适配器数据的定义

package com.proj.linkage

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.proj.linkage.TopItemAdpater.TabViewHolder

/**
 * 头部列表
 */
class TopItemAdpater(private val context: Context) : RecyclerView.Adapter<TabViewHolder>() {
    private var datas: List<String>? = null
    fun setDatas(datas: List<String>?) {
        this.datas = datas
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): TabViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.layout_item_scroll, viewGroup, false)
        return TabViewHolder(view)
    }

    override fun onBindViewHolder(tabViewHolder: TabViewHolder, i: Int) {
        tabViewHolder.mTabTv.text = datas!![i]
    }

    override fun getItemCount(): Int {
        return if (null == datas) 0 else datas!!.size
    }

    inner class TabViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var mTabTv: TextView

        init {
            mTabTv = itemView.findViewById(R.id.tv_right_scroll)
        }
    }

}

通过TopItemAdpater来实现头部RecyclerView的数据绑定功能,然后设置头部RecyclerView中,
在子条目数据横向滚动的时候同步更新数据

2.2.5 Acvitiy中实现数据的绑定和调用

  package com.proj.linkage

import android.app.Activity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import java.util.*

class SwipeRefreshActivity : Activity() {
    private var rvTabRight: RecyclerView? = null
    private var recyclerContent: RecyclerView? = null
    private var swipeRefresh: SwipeRefreshLayout? = null
    private val mEntities: MutableList<DataEntity> = ArrayList()
    private val rightMoveDatas: MutableList<String> = ArrayList()
    private val topTabs: MutableList<String> = ArrayList()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_swipe)
        rvTabRight = findViewById(R.id.rv_tab_right) as RecyclerView
        recyclerContent = findViewById(R.id.recycler_content) as RecyclerView
        swipeRefresh = findViewById(R.id.swipe_refresh) as SwipeRefreshLayout
        //处理顶部标题部分
        val linearLayoutManager = LinearLayoutManager(this)
        linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
        rvTabRight!!.setLayoutManager(linearLayoutManager)
        val topTabAdpater = TopItemAdpater(this)
        rvTabRight!!.setAdapter(topTabAdpater)
        for (i in 1..19) {
            topTabs.add(i.toString() + "年级")
        }
        topTabAdpater.setDatas(topTabs)
        //处理内容部分
        recyclerContent!!.setLayoutManager(LinearLayoutManager(this))
        recyclerContent!!.setHasFixedSize(true)
        val contentAdapter = ContentAdapter(this, rvTabRight!!)
        recyclerContent!!.setAdapter(contentAdapter)
        recyclerContent!!.postDelayed(Runnable {
            for (i in 1..19) {
                val dataEntity = DataEntity()
                rightMoveDatas.clear()
                for (j in 1..19) {
                    rightMoveDatas.add(j.toString() + "班")
                }
                dataEntity.rightDatas = rightMoveDatas
                mEntities.add(dataEntity)
            }
            contentAdapter.setDatas(mEntities)
            Toast.makeText(this@SwipeRefreshActivity, "加载完毕,加载了30条数据", Toast.LENGTH_SHORT).show()
        }, 1500)

        //下拉刷新
        swipeRefresh!!.setOnRefreshListener(OnRefreshListener {
            recyclerContent!!.postDelayed(Runnable {
                for (i in 1..29) {
                    val dataEntity = DataEntity()
                    rightMoveDatas.clear()
                    for (j in 1..29) {
                        rightMoveDatas.add(j.toString() + "班")
                    }
                    dataEntity.rightDatas = rightMoveDatas
                    mEntities.add(dataEntity)
                }
                contentAdapter.setDatas(mEntities)
                swipeRefresh!!.setRefreshing(false)
                Toast.makeText(this@SwipeRefreshActivity, "刷新完毕,刷新了50条数据", Toast.LENGTH_SHORT).show()
            }, 1500)
        })
    }
}

在这个类里面实现对数据的绑定,下滑加载数据,头部数据和子条目数据的绑定,实现自定义RecyclerView横竖屏滚动
加载数据,

2.2.6 xml布局文件

 activity_swipe.xml
   <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".SwipeRefreshActivity">

    <LinearLayout
        android:id="@+id/ll_top_root"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:visibility="visible">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_tab_right"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"
            android:scrollbars="none">
        </androidx.recyclerview.widget.RecyclerView>

    </LinearLayout>

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

        </androidx.recyclerview.widget.RecyclerView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</LinearLayout>

layout_item_content.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:orientation="horizontal">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_item_right"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        android:scrollbars="none">

    </androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

layout_item_scroll.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="120dp"
    android:layout_height="80dp"
    android:orientation="vertical">

    <TextView
        android:gravity="center"
        android:id="@+id/tv_right_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textColor="#000000" />
</LinearLayout>

猜你喜欢

转载自blog.csdn.net/baidu_41666295/article/details/127491340