Пользовательское представление Android: как обновить пользовательский атрибут enum с помощью LiveData и привязки данных - PullRequest
0 голосов
/ 05 мая 2019

Я создаю пользовательское представление, которое имеет несколько пользовательских атрибутов, два из которых являются перечислениями.Я использую привязку данных и MutableLiveData для обновления моих представлений.Это работает без проблем, но у меня возникают проблемы с тем, чтобы заставить его работать с моим enum.Кто-нибудь может помочь?

Все примеры кода были обрезаны, чтобы показать только то, что связано с проблемой.Если что-то важное отсутствует, пожалуйста, укажите это.Это мой макет:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        >

    <data>
        <variable
                name="viewModel"
                type="com.myapp.wifi.WifiItemViewModel"
                />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/margin_16"
            android:paddingBottom="@dimen/margin_16"
            >

        <components.wifi.WifiIconComponent
                android:id="@+id/img_wifi_icon"
                style="@style/WrapContent"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_marginEnd="8dp"
                app:wifiState="@{viewModel.wifiState}"
                app:termsAndConditionsAccepted="@{viewModel.termsAccepted}"
                app:layout_constraintEnd_toEndOf="@id/guideline_start"
                app:layout_constraintTop_toTopOf="parent"
                />

        <TextView
                android:id="@+id/text_wifi_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textAppearance="@style/H5"
                android:text="@{viewModel.wifiName}"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toEndOf="@id/guideline_start"
                app:layout_constraintEnd_toEndOf="@id/guideline_end"
                />

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

Мой пользовательский вид - WifiIconComponent.Вот как я объявляю его пользовательские атрибуты в attrs.xml:

 <declare-styleable name="WifiIconComponent">
        <attr name="wifiState" format="enum">
            <enum name="NotAdded" value="0"/>
            <enum name="NotAvailable" value="1"/>
            <enum name="Available" value="2"/>
            <enum name="ConnectedWithoutInternet" value="3"/>
            <enum name="Connected" value="4"/>
        </attr>
        <attr name="termsAndConditionsAccepted" format="boolean"/>
        <attr name="iconSizing" format="enum">
            <enum name="small" value="0"/>
            <enum name="medium" value="1"/>
            <enum name="large" value="2"/>
        </attr>
    </declare-styleable>

И это файл класса представления:

class WifiIconComponent @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ImageView(context, attrs, defStyleAttr) {

    private var wifiState = WifiState.NOT_ADDED
    private var termsAndConditionsAccepted = false
    private var iconSize = WifiIconSize.SMALL

    init {
        attrs?.let {
            val attributes = context.obtainStyledAttributes(it, R.styleable.WifiIconComponent)
            termsAndConditionsAccepted =
                attributes.getBoolean(R.styleable.WifiIconComponent_termsAndConditionsAccepted, false)
            iconSize = WifiIconSize.values()[attributes.getInt(R.styleable.WifiIconComponent_iconSizing, 0)]
            wifiState = WifiState.values()[attributes.getInt(R.styleable.WifiIconComponent_wifiState, 0)]
            attributes.recycle()
        }
        setImageDrawable(getStateIcon())
    }

    private fun getStateIcon(): Drawable? {
        val resource = when (iconSize) {
            WifiIconSize.SMALL -> getSmallIcon()
            WifiIconSize.MEDIUM -> getMediumIcon()
            WifiIconSize.LARGE -> getLargeIcon()
        }
        return context.getDrawable(resource)
    }

// rest of class

}

Это модель представления, указанная в макете:

class WifiItemViewModel(state: WifiConnectionState, val termsAccepted: Boolean) {

    val description = dummyArg.description
    var wifiState = MutableLiveData(state.wifiState)
    val wifiStateAsString = MutableLiveData(wifiState.value.toString())
    val wifiName = MutableLiveData(state.name)
    val switchVisibility = MutableLiveData(View.GONE)
    val activationState = MutableLiveData(state.isActivated)

    // the rest of the class is unrelated to the problem

}

Теперь, если я просто установлю любое значение в макете, например, app:wifiState="Connected" , все будет работать нормально.В блоке init заданное значение корректно переводится в правильное состояние моего перечисления в коде:

enum class WifiState {
    NOT_ADDED,
    NOT_AVAILABLE,
    AVAILABLE,
    CONNECTED_WITHOUT_INTERNET,
    CONNECTED_WITH_INTERNET
}

Но если я связываю его с MutableLiveData в моей viewModel (как я делаю в приведенном выше макете), я получаю эту ошибку:

****/ data binding error ****msg:Cannot find the setter for attribute 'app:wifiState' with parameter type androidx.lifecycle.MutableLiveData<components.wifi.WifiState> on components.wifi.WifiIconComponent.

Я предполагаю, что это связано с наличием в основном двух разных перечислений для одинаковых значений, одного в коде и одного в xml.Есть ли другой способ сделать это?Или, если мой подход в порядке, как мне заставить его работать?Кто может помочь?

1 Ответ

0 голосов
/ 06 мая 2019

Это не может быть реальным ответом, но, тем не менее, именно так я решил свою проблему: я понял, что могу просто определить пользовательские целые числа в res/values/integers.xml, поэтому я просто избавился от своих перечислений и переключился на целые числа, которые могут легко быть доступным как в файлах макетов, так и в классах Java / Kotlin. Этот ответ на другой вопрос хорошо описывает, как это работает. Затем эти целые числа можно легко передать в LiveData и обновить представление.

...