智慧团建网站首页谷歌广告上海有限公司官网
文章目录
- 前言
- 1、效果展示
- 2、布局
- 关键代码实现
- 内层RecyclerView的适配器
- 自定义RecyclerView
- 外层RecyclerView的适配器
- 数据实现
- 页面布局
- 主页面(templater_table_fragment.xml)
- 嵌套页面(templater_table_fragment_table_rv.xml)
- 嵌套子页面布局(template_table_record_recycler_view.xml)
前言
在Android中没有控件可以直接展示表格,但是有的时候又需要构建类似于表格的布局,通过RecyclerView直接嵌套实现表格,但是需要实现嵌套RecyclerView的子项实现水平方向联动滑动的效果比较麻烦,接下来看一下如何实现。
1、效果展示
表格水平滑动
2、布局
关键代码实现
内层RecyclerView的适配器
在onCreateViewHolder的方法,
绑定需要的同步的子项SyncHorizontalScrollRecyclerView,
在onBindViewHolder的方法中,初始化子项SyncHorizontalScrollRecyclerView
class TableChildAdapter<T>(val context: Context, val type:Int, val mutableList: T):RecyclerView.Adapter<TableChildAdapter.TableViewHolder>() {private val horizontalViews = mutableListOf<SyncHorizontalScrollRecyclerView>()override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {val view = LayoutInflater.from(context).inflate(R.layout.template_table_record_recycler_view,parent,false)return TableViewHolder(view).apply {sampleRecyclerView.addToSyncGroup(*horizontalViews.toTypedArray())horizontalViews.add(sampleRecyclerView)}}override fun getItemCount(): Int {return (mutableList as MutableList<*>).size}@SuppressLint("ClickableViewAccessibility")override fun onBindViewHolder(holder: TableViewHolder, position: Int) {if (type == RECORD_TYPE_GRID){holder.textView.text = (mutableList as MutableList<*>)[position] as Stringif (position %2 == 1) {holder.textView.textSize = context.fontSizeOf(10)holder.textView.setTextColor(context.getColor(R.color.purple_700))}}else{holder.textView.visibility = View.GONEval innerAdapter = initInnerAdapter(position)with(holder.sampleRecyclerView){layoutManager = LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false)adapter = innerAdapterinnerAdapter.submitList((mutableList as MutableList<*>)[position] as List<String>?)}}}private fun initInnerAdapter(position: Int): BaseQuickAdapter<String,QuickViewHolder> {return object : BaseQuickAdapter<String, QuickViewHolder>(){override fun onBindViewHolder(holder: QuickViewHolder,subposition: Int,item: String?) {val textItem = holder.itemView.findViewById<TextView>(R.id.table_sample_key)textItem.text = itemif (position != 0){textItem.setTextColor(context.getColor(R.color.purple_700))textItem.textSize = context.fontSizeOf(10)}}override fun onCreateViewHolder(context: Context,parent: ViewGroup,viewType: Int): QuickViewHolder {return QuickViewHolder(LayoutInflater.from(context).inflate(R.layout.template_table_sample_recycler_view,parent,false))}}}class TableViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){var textView: TextView = itemView.findViewById(R.id.table_record_key)val sampleRecyclerView:SyncHorizontalScrollRecyclerView = itemView.findViewById(R.id.table_sample_key_rv)}companion object {val RECORD_TYPE_GRID = 0val SAMPLE_TYPE_LIN = 1}
}
自定义RecyclerView
在SyncHorizontalScrollRecyclerView中添加滑动监听,在OnScrollListener中进行同步滑动
class SyncHorizontalScrollRecyclerView(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) {// 同步滚动组(所有需要联动的RecyclerView)private val syncGroup = mutableListOf<SyncHorizontalScrollRecyclerView>()private var firstPos = 0private var firstOffset = 0init {overScrollMode = OVER_SCROLL_NEVER // 禁用边缘发光效果//性能优化this.setHasFixedSize(true)val layoutManager = this.layoutManager as LinearLayoutManager?// 通过移动layoutManager来实现列表滑动 此行是让新加载的item条目保持跟已经滑动的recycleView位置保持一致// 也就是上拉加载更多的时候 保证新加载出来的item 跟已经滑动的item位置保持一致if (layoutManager != null && firstPos > 0 && firstOffset > 0) {layoutManager.scrollToPositionWithOffset(firstPos + 1, firstOffset)}//添加当前滑动recycleView的滑动监听this.addOnScrollListener(object : OnScrollListener() {override fun onScrolled(currentRV: RecyclerView, dx: Int, dy: Int) {super.onScrolled(currentRV, dx, dy)val currentLM = currentRV.layoutManager as LinearLayoutManager//获取显示第一个item的位置val currentItemPos = currentLM.findFirstVisibleItemPosition()val currentItem = currentLM.getChildAt(0)if (currentItem != null) {//获取第一个item的偏移量val firstRight = currentLM.getDecoratedRight(currentItem)//遍历其它的所有的recycleView条目syncGroup.forEach { otherRV->if (currentRV != otherRV){val otherLayoutManager = otherRV.layoutManager as LinearLayoutManagerfirstPos = currentItemPosfirstOffset = firstRight//通过当前显示item的位置和偏移量的位置来置顶recycleView 也就是同步其它item的移动距离otherLayoutManager.scrollToPositionWithOffset( currentItemPos + 1, firstRight)}}}}})}// 加入同步组fun addToSyncGroup(vararg views: SyncHorizontalScrollRecyclerView) {syncGroup.addAll(views)views.forEach { it.syncGroup.add(this) }}}
关键实现代码:
otherLayoutManager.scrollToPositionWithOffset( currentItemPos + 1, firstRight)
外层RecyclerView的适配器
添加依赖
implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:4.0.0-beta14"
BaseQuickAdapter继承于RecyclerView.Adapter,将一些多余的方法进行封装
class TableParentAdapter:BaseQuickAdapter<TableTempBean,QuickViewHolder>() {override fun onBindViewHolder(holder: QuickViewHolder, position: Int, item: TableTempBean?) {//现场记录数据——宫格数据 key-value显示with(holder.itemView.findViewById<TextView>(R.id.template_name)){text = item?.templateName ?:"模板名称"}with(holder.itemView.findViewById<RecyclerView>(R.id.table_record_rv)){layoutManager = GridLayoutManager(context,4)adapter = TableChildAdapter(context, TableChildAdapter.RECORD_TYPE_GRID,item?.recordData?: mutableListOf())}//采样数据的具体值with(holder.itemView.findViewById<RecyclerView>(R.id.table_sample_value)){layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)adapter = TableChildAdapter(context,TableChildAdapter.SAMPLE_TYPE_LIN,item?.sampleData?: mutableListOf())}}override fun onCreateViewHolder(context: Context,parent: ViewGroup,viewType: Int): QuickViewHolder {return QuickViewHolder(LayoutInflater.from(context).inflate(R.layout.templater_table_fragment_table_rv,parent,false))}
}
数据实现
val temList = mutableListOf<TableTempBean>()val tableBean = TableTempBean()//标题tableBean.templateName = "模板名称"tableBean.recordData = mutableListOf("电话","15787","名字","刘")tableBean.sampleData = mutableListOf(mutableListOf("地点","编号","时间","温度","感官","状况"),mutableListOf("厦门","01","21:00","温度1","感官1","状况1"),mutableListOf("泉州","02","20:00","温度2","感官2","状况2"),mutableListOf("福州","03","18:00","温度3","感官3","状况3"),mutableListOf("龙岩","04","15:00","温度4","感官4","状况4"),mutableListOf("漳州","05","12:00","温度5","感官5","状况5"))temList.add(tableBean)with(binding.templeRv){val temAdapter = TableParentAdapter()layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)adapter = temAdaptertemAdapter.submitList(temList)}
页面布局
主页面(templater_table_fragment.xml)
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/temple_rv"android:layout_width="match_parent"android:layout_height="500dp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
嵌套页面(templater_table_fragment_table_rv.xml)
两个recyclerView控件直接实现会导致滑动出错,将所有数据加载出来,使用ScrollView实现垂直方向的滑动。(要是有其他更好地实现方式实现可以告诉我就更好啦)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/template_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:padding="@dimen/dp_10"android:text="模板名称"android:textSize="@dimen/dp_20"android:textStyle="bold" /><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/table_record_rv"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/template_name" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/table_sample_value"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/table_record_rv"/></LinearLayout></ScrollView>
</LinearLayout>
嵌套子页面布局(template_table_record_recycler_view.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:id="@+id/table_record_key"android:layout_width="@dimen/table_text_width"android:layout_height="@dimen/table_text_height"android:gravity="center"android:background="@drawable/table_adapter_bg"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:textSize="@dimen/table_text_size"android:text="企业代表或代理人签章" /><app.environmental.testing.ui.adapter.SyncHorizontalScrollRecyclerViewandroid:id="@+id/table_sample_key_rv"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/table_record_key"/>
</androidx.constraintlayout.widget.ConstraintLayout>
关键代码实现:Android 使用三个Reyclerview 实现表格布局,支持横向纵向滑动