首页 > 解决方案 > AirBnb Epoxy - 视图被复制而不是被替换

问题描述

我正在渲染基于从服务器获取的 JSON 响应的表单。

我的用例包括监听单选按钮的点击,根据单选按钮选择切换某些文本字段的可见性,并使用可见的 textView 刷新布局。

预期的输出应该是用现在可见的 textView 更新同一个视图,但我现在看到同一个表单两次,第一次是默认状态,第二次是更新状态。

我是否以某种方式创建了一个全新的model_类并将其传递给控制器​​?我只想更改现有模型的布尔字段并更新视图。

我的模特班

@EpoxyModelClass(layout = R.layout.layout_panel_input)
abstract class PanelInputModel(
    @EpoxyAttribute var panelInput: PanelInput,
    @EpoxyAttribute var isVisible: Boolean,
    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var context: Context,
    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var textChangedListener: InputTextChangedListener,
    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var radioButtonSelectedListener: RadioButtonSelectedListener,
    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var validationChangedListener: ValidationChangedListener
) : EpoxyModelWithHolder<PanelInputModel.PanelInputHolder>() {

    @EpoxyAttribute var imageList = mutableListOf<ImageInput>()

    override fun bind(holder: PanelInputHolder) {
        val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        generateViews(holder, inflater, panelInput.elements) // Generates textViews, radioButtons, etc, based on ElementType enum inside Panel input
    }

   fun generateRadioButtonView(element: Element) {
        // Created a custom listener and calling its function
        radioButtonSelectedListener.radioButtonSelected(chip.id, chip.text.toString())
   }

  fun generateTextView() {
     // Show/hide textView based on isVisible value
  }

我的控制器类

class FormInputController(
    var context: Context,
    var position: Int, // Fragment Position in PagerAdapter
    var textChangedListener: InputTextChangedListener,
    var radioButtonSelectedListener: RadioButtonSelectedListener,
    var validationChangedListener: ValidationChangedListener
) : TypedEpoxyController<FormInput>() {

    override fun buildModels(data: FormInput?) {
        val panelInputModel = PanelInputModel_(
            data as PanelInput,
            data.isVisible,
            context,
            textChangedListener,
            radioButtonSelectedListener,
            validationChangedListener
        )
        panelInputModel.id(position)
        panelInputModel.addTo(this)
    }
}

我的片段实现了单选按钮选中的侦听器,修改formInput.isVisible = true并调用formInputController.setData(componentList)

请帮我解决这个问题,谢谢!

标签: androidandroid-recyclerviewepoxyepoxy-modelview

解决方案


我认为您没有正确使用环氧树脂,这不是应该的。

  1. 首先,让我们从 Holder 开始:您不应该在 bind/unbind 中膨胀视图,只需在此处设置视图即可。此外,视图会从您指定的布局文件中为您膨胀R.layout.layout_panel_input,因此根本不需要膨胀。

您应该将其复制到您的项目中: https ://github.com/airbnb/epoxy/blob/master/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinEpoxyHolder.kt

并以这种方式创建您的持有人:

class PanelInputHolder : KotlinHolder() {

    val textView by bind<TextView>(R.id.your_text_view_id)
    val button by bind<Button>(R.id.your_button_id)
}
  1. 让我们转到您的模型类:您应该从构造函数中删除这些变量,因为它们将成为注释处理器创建实际类的引用。另外,不要从注释中设置布局资源,因为将来不允许这样做。

像这样:

@EpoxyModelClass
class PanelInputModel : EpoxyModelWithHolder<PanelInputHolder>() {

    @EpoxyAttribute
    lateinit var text: String
    @EpoxyAttribute(DoNotHash)
    lateinit var listener: View.OnClickListener

    override fun getDefaultLayout(): Int {
        return R.layout.layout_panel_input
    }

    override fun bind(holder: PanelInputHolder) {

        // here set your views
        holder.textView.text = text
        holder.textView.setOnClickListener(listener)
    }

    override fun unbind(holder: PanelInputHolder) {

        // here unset your views
        holder.textView.text = null
        holder.textView.setOnClickListener(null)
    }
}
  1. 在控制器内部而不是模型内部循环您的数据:

class FormInputController : TypedEpoxyController<FormInput>() {
    
    
    override fun buildModels(data: FormInput?) {
    
        data?.let {

            // do your layout as you want, with the models you specify
            // for example a header
        
            PanelInputModel_()
                .id(it.id)
                .text("Hello WOrld!")
                .listener { // do something here }
                .addTo(this)
        
            // generate a model per item
            it.images.forEach {
            
                ImageModel_()
                    .id(it.imageId)
                    .image(it)
                    .addTo(this)
            }
        }
    }
}

选择您的 id 时,请记住 Epoxy 将跟踪这些并在 attrs 更改时更新,因此不要使用位置,而是使用不会重复的唯一 id。


推荐阅读