AirBnb Epoxy — представления дублируются, а не заменяются

Я отображаю форму на основе ответа JSON, который я получаю с сервера.

Мой вариант использования включает в себя прослушивание щелчка радиокнопки, переключение видимости определенных текстовых полей на основе выбора radioButton и обновление макета с помощью видимого 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)

Пожалуйста, помогите мне в этом, спасибо!

1 ответ

Я не думаю, что вы правильно используете эпоксидную смолу, это не так, как должно быть.

  1. Прежде всего, начнем с холдера: не стоит раздувать вьюху внутри 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)
            }
        }
    }
}

Выбирая свой идентификатор, имейте в виду, что Epoxy будет отслеживать их и обновлять, если атрибуты изменятся, поэтому используйте не позицию, а уникальный идентификатор, который не будет дублироваться.

Другие вопросы по тегам