Как двухстороннее связывание Seekbar в пользовательском представлении / компоненте? - PullRequest
0 голосов
/ 06 марта 2019

Я пытаюсь использовать двустороннюю привязку данных в пользовательском представлении, которое содержит SeekBar.Макет довольно прост, но мне нужно повторно использовать его по всему проекту, следовательно, обернуть его в пользовательский вид / компонент

<androidx.constraintlayout.widget.ConstraintLayout   ... />

<TextView .../>
<TextView .../>

<SeekBar
    android:id="@+id/ds_seekbar"
    android:layout....
    android:max="9"
    android:min="0"
    android:progress="0"
   </androidx.constraintlayout.widget.ConstraintLayout>

Код поддержки выглядит так (уменьшено)

CustomView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0

) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {

    init {
        LayoutInflater.from(context).inflate(R.layout.custom_view, this, true)
        ds_description.setOnClickListener(this)

    }

    override fun onClick(view: View) {
//onClick implementation 
        }
}

Я могу сделать привязку во ViewModel для макета, где будет использоваться это настраиваемое представление, с помощью BindingAdapter с настраиваемым атрибутом (например, app: seekbar), но настраиваемое представление будет использоваться несколько раз, и я 'Я предпочел бы иметь большую логику, необходимую для представления, и иметь более «легкую» обработку в ViewModel.

Я читаю Двухстороннее связывание данных Android с пользовательским представлением и пользовательским атрибутом и кучу других статей, которые, кажется, немного отличаются, но на одну и ту же тему, однако независимо от того, как я написал геттер и сеттеры, я всегда сталкиваюсь с исключением из kapt, что он не может найти геттер / сеттер.

Либо я не правильно аннотирую методы, либо они имеют неправильные подписи.

В идеале я хочу иметь что-то вроде:

   CustomView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0

) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener, SeekBar.OnProgressChangedListener {

... ds_seekbar.setOnProgressChangedListener(this)

А затем в главном макете есть приложение: прогресс (или даже лучше, если кто-то может показать, как это делается на Android: прогресс) напользовательский вид для привязки при передаче моего объекта.

1 Ответ

0 голосов
/ 08 марта 2019

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

@InverseBindingMethods(InverseBindingMethod(type = CustomView::class, attribute = "progress", event = "progressAttrChanged"))
CustomView @JvmOverloads constructor(...

private var progress = 0
private var mInverseBindingListener: InverseBindingListener? = null


cv_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
            progress = i + 1
            if (mInverseBindingListener != null) {
                mInverseBindingListener!!.onChange()
                cv_indicator.text = progress.toString()
            }
        }...
   })

fun getProgress(): Int {
    return progress
}

fun setProgress(p: Int) {
    if (progress != p) {
        progress = p
    }
}

fun setProgressAttrChanged(inverseBindingListener: InverseBindingListener?) {
    if (inverseBindingListener != null) {
        mInverseBindingListener = inverseBindingListener
    }
}

Тогда XML будет

 <com.xxx.CustomView
                android:id="@+id/xxx"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:progress="@={viewModel.dataobject.value}"
          ....
                />
...