【问题标题】:How to implement a custom view in a RecyclerView using a BindingAdapter如何使用 BindingAdapter 在 RecyclerView 中实现自定义视图
【发布时间】:2021-05-14 09:11:25
【问题描述】:

谁能帮助我使用绑定适配器在 RecyclerView(显示一些 speedcubing 会话的数据)中使用自定义视图(AAChartCore-Kotlin,ChartView)?

我已经尝试将 ChartView 添加到 RecyclerView 项目列表并为它实现一个 BindingAdapter,我调用 aa_drawChartWithChartModel(...),它应该在图表中显示数据,将项目的 chartModel 传递给它,但我没有想法是否正确。

目前,图表似乎已加载到视图中,但它是不可见的。

list_item_session.xml

<!-- ... -->

</LinearLayout>

    <!-- ... -->

    </HorizontalScrollView>

        <!-- ... -->

        </androidx.constraintlayout.widget.ConstraintLayout>

            <!-- ... -->

            <com.github.aachartmodel.aainfographics.aachartcreator.AAChartView

                android:id="@+id/sessionChart"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/margin_big"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/sessionEndDateTime"
                app:layout_constraintTop_toTopOf="parent"
                app:sessionChartView="@{session}">

            </com.github.aachartmodel.aainfographics.aachartcreator.AAChartView>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </HorizontalScrollView>


</LinearLayout>

SessionAdapter.kt

class SessionAdapter(private val clickListener: SessionListener) : ListAdapter<DataItem, RecyclerView.ViewHolder>(SessionsDiffCallback()) {

    /* PROPERTIES */

    // Coroutines
    private val adapterScope = CoroutineScope(Dispatchers.Default)


    /* COMPANION OBJECT */

    companion object
    {
        private const val ITEM_VIEW_TYPE_PADDING = 0
        private const val ITEM_VIEW_TYPE_SESSION = 1
    }


    /* ADAPTER METHODS */

    fun submitListWithPadding(list: List<Session>?) {
        adapterScope.launch {
            val items = when(list) {
                null -> listOf(DataItem.PaddingItem)
                else -> list.map { DataItem.SessionItem(it) } + listOf(DataItem.PaddingItem)
            }
            withContext(Dispatchers.Main) {
                submitList(items)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when(viewType) {
            ITEM_VIEW_TYPE_PADDING -> TextViewHolder.from(parent)
            ITEM_VIEW_TYPE_SESSION -> ViewHolder.from(parent)

            else -> throw ClassCastException("Unknown viewType $viewType")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when(holder) {
            is ViewHolder -> {
                val sessionItem = getItem(position) as DataItem.SessionItem
                holder.bind(clickListener, sessionItem.session)
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when(getItem(position)) {
            is DataItem.PaddingItem -> ITEM_VIEW_TYPE_PADDING
            is DataItem.SessionItem -> ITEM_VIEW_TYPE_SESSION
        }
    }


    /* VIEW HOLDER FOR SESSION ITEMS */

    class ViewHolder private constructor(val binding: ListItemSessionBinding) : RecyclerView.ViewHolder(binding.root)
    {
        fun bind(clickListener: SessionListener, item: Session) {
            binding.session = item
            binding.clickListener = clickListener
            binding.executePendingBindings()
        }

        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = ListItemSessionBinding.inflate(layoutInflater, parent, false)

                return ViewHolder(binding)
            }
        }
    }


    /* TEXT VIEW HOLDER FOR PADDING ITEM */

    class TextViewHolder(view: View) : RecyclerView.ViewHolder(view)
    {
        companion object
        {
            fun from(parent: ViewGroup): TextViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val view = layoutInflater.inflate(R.layout.list_item_padding, parent, false)

                return TextViewHolder(view)
            }
        }
    }
}

BindingAdapters.kt

/* ... */

@BindingAdapter("sessionChartView")
fun AAChartView.setSessionChartView(item: Session?) {
    item?.let {
        aa_drawChartWithChartModel(it.chartModel)
    }
}

DataItem.kt

sealed class DataItem
{
    abstract val id: Long

    data class SessionItem(val session: Session) : DataItem()
    {
        override val id = session.id
    }

    object PaddingItem : DataItem()
    {
        override val id = Long.MIN_VALUE
    }
}

SessionsDiffCallback.kt

class SessionsDiffCallback : DiffUtil.ItemCallback<DataItem>()
{
    override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
        return oldItem == newItem
    }
}

【问题讨论】:

    标签: android kotlin android-recyclerview android-custom-view android-binding-adapter


    【解决方案1】:

    您应该将视图设置为参数并在您的 BindingAdapter 中调用它的方法。

    @BindingAdapter("sessionChartView")
    @JvmStatic
    fun setSessionChartView(view: AAChartView, item: Session?) {
        item?.let {
            view.aa_drawChartWithChartModel(it.chartModel)
        }
    }
    

    【讨论】:

    • 我尝试复制您发布的代码,但看起来并没有改变任何内容。
    • AAChartModel 文档中写道,aa_drawChartWithChartModel 方法仅在您创建 AAChartView 实例对象后第一次被调用。当您的BindingAdapter 第一次调用list 时可能是空的。之后aa_drawChartWithChartModel 方法不起作用。尝试使用aa_onlyRefreshTheChartDataWithChartModelSeriesaa_refreshChartWholeContentWithChartModel方法重绘图表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    • 2015-03-21
    相关资源
    最近更新 更多