RecyclerView с группами
Какой компонент тут используется? Это RecyclerView с разными ViewHolder? А как добавить возможность раскрывать/скрывать?
Ответы (2 шт):
Все что касается UI - то там нет никаких стандартов. Это может быть все что угодно, и я думаю, что ребята из Сбербанка там вообще реализовывали свою View.
Что вы можете сделать для похожего эффекта? Мне напрашивается пару самых очевидных вариантов:
Как вы и заметили это может быть
RecyclerViewс разнымиViewHolder-ами. КаждыйViewHolderэто отдельнаяViewв которой скрыта вся логика (в том числе сворачивания и разворачивания). Для этого вам скорее всего придется использовать какой-то самописный CompoundView.В чем тут проблема: если там будет много сложной логики - вам придется очень заморочиться с тем чтоб это все сделать работоспособным и потом поддерживать.
В целом это может быть какой-нибудь
NestedScrollViewв который вы ручками будете добавлять фрагменты (каждый элемент ==Fragment). Внутри фрагмента вы будете работать как с отдельным маленьким экраном, где и опишете свою логику.Сложность тут в том, что вам возможно придется решать проблемы скролла и других штук которые уже реализованы в
RecyclerView.
Но тут может быть и миллион других вариантов. Компании такого уровня очень часто пишут свои решения. Это могут быть как просто небольшие доработки уже существующих инструментов, так и полностью с нуля написанные элементы UI где есть гора логики.
Это можно сделать с помощью вложенного адаптера.
Анимацию можно прикрутить с помощью MaterialContainerTransform.
Например нам надо сделать раскрываемые/скрываемые списки.
Создаем основной адаптер ExpandableAdapter
class ExpandableAdapter(
private val items: List<Item>,
private val nestedClickListener: (String) -> Unit,
private val transitionFunc: (View, View, ConstraintLayout) -> Unit,
private val transitionReverse: (View, View, ConstraintLayout) -> Unit
) : RecyclerView.Adapter<ExpandableAdapter.ExpandableViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ExpandableViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: ExpandableViewHolder, position: Int) {
val item = items[position]
with(holder) {
text.text = item.text
itemView.setOnClickListener {
when (list.visibility) {
VISIBLE -> {
transitionReverse(list, text, rootLayout)
Handler().postDelayed({ list.visibility = GONE }, 550)
}
GONE -> {
transitionFunc(text, list, rootLayout)
list.visibility = VISIBLE
}
}
list.adapter = NestedAdapter(item.nestedItems) { nestedClickListener(it) }
}
}
}
class ExpandableViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val rootLayout: ConstraintLayout = view.root_layout
val text: TextView = view.text
val list: RecyclerView = view.recycler
}
}
И вложенный NestedAdapter
class NestedAdapter(
private val items: List<String>,
private val clickListener: (String) -> Unit
) : RecyclerView.Adapter<NestedAdapter.NestedViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NestedViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: NestedViewHolder, position: Int) {
val item = items[position]
with(holder) {
text.text = item
itemView.setOnClickListener { clickListener(item) }
}
}
class NestedViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val text: TextView = view.text
}
}
Activity
class ExpandableListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_expandable_list)
main_recycler.setHasFixedSize(true)
main_recycler.adapter = ExpandableAdapter(getItems(), {
Toast.makeText(this, it, LENGTH_SHORT).show()
},{ startView, endView, rootLayout ->
beginDelayedTransition(rootLayout, startView.getTransform(endView))
}, { startView, endView, rootLayout ->
beginDelayedTransition(rootLayout, startView.getTransform(endView))
})
}
private fun getItems() = listOf(
Item(12, "первый", listOf("1", "2", "3")),
Item(13, "второй", listOf("4", "5", "6")),
Item(24, "третий", listOf("7", "8", "9")),
Item(37, "четвертый", listOf("10", "11", "12")),
Item(19, "пятый", listOf("13", "14", "15"))
)
private fun View.getTransform(mEndView: View) = MaterialContainerTransform().apply {
startView = this@getTransform
endView = mEndView
addTarget(mEndView)
pathMotion = MaterialArcMotion()
duration = 550
scrimColor = Color.TRANSPARENT
}
}
В айтеме будет RecyclerView с заголовком:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@android:string/unknownName" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text"
tools:itemCount="5"
tools:listitem="@android:layout/simple_list_item_1"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
Item
data class Item(
val id: Int,
val text: String,
val nestedItems: List<String>
)
activity_expandable_list
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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_height="wrap_content"
tools:context=".expandable.ExpandableListActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item" />
</FrameLayout>

