From 4f8040a970291abc464f0b2b8dbf6ce2c303ca35 Mon Sep 17 00:00:00 2001 From: WhiredPlanck Date: Fri, 18 Oct 2024 22:43:11 +0800 Subject: [PATCH] refactor: transform LiquidTabsUi with RecyclerView fix: selected tab index out of bounds --- .../osfans/trime/ime/symbol/LiquidTabsUi.kt | 116 +++++++++--------- 1 file changed, 57 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/osfans/trime/ime/symbol/LiquidTabsUi.kt b/app/src/main/java/com/osfans/trime/ime/symbol/LiquidTabsUi.kt index 9fbac382f7..4db17a475a 100644 --- a/app/src/main/java/com/osfans/trime/ime/symbol/LiquidTabsUi.kt +++ b/app/src/main/java/com/osfans/trime/ime/symbol/LiquidTabsUi.kt @@ -7,7 +7,9 @@ package com.osfans.trime.ime.symbol import android.content.Context import android.graphics.Color import android.graphics.drawable.PaintDrawable -import android.widget.HorizontalScrollView +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter4.BaseQuickAdapter import com.osfans.trime.data.theme.ColorManager import com.osfans.trime.data.theme.FontManager import com.osfans.trime.data.theme.Theme @@ -16,14 +18,14 @@ import splitties.dimensions.dp import splitties.views.dsl.core.Ui import splitties.views.dsl.core.add import splitties.views.dsl.core.frameLayout -import splitties.views.dsl.core.horizontalLayout import splitties.views.dsl.core.lParams import splitties.views.dsl.core.matchParent import splitties.views.dsl.core.textView import splitties.views.dsl.core.wrapContent +import splitties.views.dsl.recyclerview.recyclerView import splitties.views.gravityCenter -import splitties.views.gravityCenterVertical import splitties.views.horizontalPadding +import splitties.views.recyclerview.horizontalLayoutManager class LiquidTabsUi( override val ctx: Context, @@ -32,8 +34,6 @@ class LiquidTabsUi( inner class TabUi : Ui { override val ctx = this@LiquidTabsUi.ctx - var position: Int = -1 - val text = textView { textSize = theme.generalStyle.candidateTextSize.toFloat() @@ -51,9 +51,6 @@ class LiquidTabsUi( }, ) background = rippleDrawable(ColorManager.getColor("hilited_candidate_back_color")!!) - setOnClickListener { - onTabClick(this@TabUi) - } } fun setText(str: String) { @@ -81,71 +78,72 @@ class LiquidTabsUi( } } - private var tabs: Array = arrayOf() - private var selected = -1 + private var onTabClick: ((Int) -> Unit)? = null + + private class TabUiHolder( + val ui: LiquidTabsUi.TabUi, + ) : RecyclerView.ViewHolder(ui.root) + + private val adapter by lazy { + object : BaseQuickAdapter() { + private var selected = -1 + + override fun onCreateViewHolder( + context: Context, + parent: ViewGroup, + viewType: Int, + ) = TabUiHolder(TabUi()) + + override fun onBindViewHolder( + holder: TabUiHolder, + position: Int, + item: TabTag?, + ) { + holder.ui.apply { + setText(item!!.text) + setActive(position == selected) + root.run { + layoutParams = ViewGroup.LayoutParams(wrapContent, matchParent) + } + } + } - private var onTabClick: (TabUi.(Int) -> Unit)? = null + override fun submitList(list: List?) { + selected = -1 + super.submitList(list) + } - private val horizontal = horizontalLayout() + fun activateTab(position: Int) { + if (position == selected) return + notifyItemChanged(selected) + selected = position + notifyItemChanged(position) + } + }.apply { + setOnItemClickListener { _, _, position -> + onTabClick?.invoke(position) + } + } + } override val root = - HorizontalScrollView(ctx).apply { + recyclerView { + layoutManager = horizontalLayoutManager() + adapter = this@LiquidTabsUi.adapter isVerticalScrollBarEnabled = false isHorizontalScrollBarEnabled = false - add( - horizontal, - lParams(wrapContent, matchParent) { - gravity = gravityCenterVertical - }, - ) - post { - scrollX = tabs[selected].root.left - } } fun setTabs(tags: List) { - tabs.forEach { root.removeView(it.root) } - selected = -1 - tabs = - Array(tags.size) { - val tag = tags[it] - TabUi().apply { - position = it - setText(tag.text) - setActive(false) - } - } - tabs.forEach { tabUi -> - horizontal.apply { - add( - tabUi.root, - lParams(wrapContent, matchParent) { - gravity = gravityCenter - }, - ) - } - } + adapter.submitList(tags) } fun activateTab(index: Int) { - if (index == selected) return - if (selected >= 0) { - tabs[selected].setActive(false) - } - tabs[index].also { tabUi -> - tabUi.setActive(true) - if (tabUi.root.left !in root.scrollX..root.scrollX + root.width) { - root.run { post { smoothScrollTo(tabUi.root.left, scrollY) } } - } - } - selected = index - } - - private fun onTabClick(tabUi: TabUi) { - onTabClick?.invoke(tabUi, tabUi.position) + adapter.activateTab(index) + root.post { root.scrollToPosition(index) } } - fun setOnTabClickListener(listener: (TabUi.(Int) -> Unit)? = null) { + fun setOnTabClickListener(listener: ((Int) -> Unit)? = null) { onTabClick = listener } }