Android: составной или нестандартный вид с двусторонним связыванием - PullRequest
0 голосов
/ 09 октября 2019

Я хочу создать пользовательское или составное представление (комбинацию нескольких стандартных компонентов) в Android, к которому можно привязывать переменные.

Вот простой сокращенный пример:

Новыйcontrol (view_custom.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

        <EditVext android:id="@+id/edittext_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:textStyle="bold"  android:layout_gravity="center" />
        <EditVext 
        ...
</LinearLayout>

Я хочу использовать в своем фрагменте элемент управления с двухсторонней привязкой

<com.test.controls.CustomView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            app:title="@={viewmodel.title}"
                            />

Я пытался создать attr, подобный этому

    <declare-styleable name="Custom">
      <attr name="title" format="string" />
</declare-styleable>

и

class CustomView(context: Context, attributeSet: AttributeSet?) :
    LinearLayout(context, attributeSet) {
          init {
    val a = context.obtainStyledAttributes(attributeSet, R.styleable.CustomView, 0, 0)
    val titleText = a.getString(R.styleable.CustomView_titl

    val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    inflater.inflate(R.layout.view_custom, this, true)

    edittext_title.text = titleText

    }

  fun setTitle(title String) {
    edittext_title.text = title
    }

    fun getTitleText(): String {
    return edittext_title.text.toString()
    }
}

Односторонняя привязка работает, но двусторонняя - нет.

1 Ответ

0 голосов
/ 10 октября 2019

Вот мое решение.

Я создал интерфейс для уведомления об изменении «title»

interface TwoWayBindingListener {
    fun hasChanged()
}

Затем я расширил свой класс CustomView

private var listener: TwoWayBindingListener? = null

fun addListener(twoWayBindingListener: TwoWayBindingListener) {
    listener = twoWayBindingListener
}

И вызывать метод hasChanged всякий раз, когда я изменяю заголовок внутри mit control

listener?.hasChanged()

И я добавляю эти BindingAdapters

@BindingAdapter("title")
fun set#String(customView: CustomView, t: String?) {
    if (t == null) {
    return
    }
    customView.setTitle()
}

@InverseBindingAdapter(attribute = "title", event = "titleAttrChanged")
fun getDateString(customView: CustomView): String {
    return customView.getTitle()
}

@BindingAdapter("titleAttrChanged")
fun setListener(customView: CustomView, listener: InverseBindingListener?) {
    if (listener != null) {
    customView.addListener(
        object : TwoWayBindingListener {
        override fun hasChanged() {
            listener.onChange()
        }
        })
    }
}
...