Как привязать метод RadioGroup к событию checkChanged с привязкой данных

Я искал в Интернете, как выполнить новую классную привязку данных Android через RadioGroup, и я не нашел ни одного сообщения в блоге об этом.

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

Например, вот моя RadioGroup:

      <RadioGroup
            android:id="@+id/split_type_radio"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:checkedButton="@+id/split_type_equal"
            android:gravity="center"
            <!-- which tag ? -->
            android:orientation="horizontal">

           ...

       </RadioGroup>

Как мне прикрепить метод обработчика, который будет вызываться для события RadioGroup checkChnged, которое будет срабатывать с использованием привязки данных?

Я попытался использовать onClick (не знаю, одно и то же) в файле макета и определить метод в действии и нашел его, используя это в файле макета:

   <variable
        name="handler"
        type="com.example.MainActivity"/>

  ...
   <RadioGroup
        android:onClick="handler.onCustomCheckChanged"
        .. >

И определил метод onCustomCheckChanged следующим образом:

public void onCustomCheckChanged(RadioGroup radio, int id) {
     // ...
}

Но это дает мне ошибку компиляции:

Ошибка: (58, 36) Класс слушателя android.view.View.OnClickListener с методом onClick не соответствует сигнатуре какого-либо обработчика метода.onCustomCheckChanged

Я видел много блогов, в которых упоминается, что это возможно с RadioGroup, но ни один из них не говорит, как это сделать. Как я могу справиться с этим с помощью data-binding ?


person kirtan403    schedule 10.09.2016    source источник
comment
Вы смотрели на этот ответ? Я думаю, вы можете сделать что-то подобное. Если вам все еще нужна помощь. в понедельник посмотрю :)   -  person yennsarah    schedule 11.09.2016
comment
@Amylinn Спасибо за ссылку. Я очень ценю это :) Я могу попробовать, но для какого атрибута я должен сделать это в xml? Как и для события checkChanged в переключателе, нет атрибута, который позволяет мне предоставить метод. В то время как «onClick» может не работать, если я прагматично изменю переключатель (например, кнопка сброса переключится на значения по умолчанию).   -  person kirtan403    schedule 11.09.2016
comment
Я думаю, что соответствующий атрибут будет app:onCheckedChangeListener.   -  person yennsarah    schedule 11.09.2016
comment
@Amylinn Понятно! Опубликовал ответ.   -  person kirtan403    schedule 11.09.2016


Ответы (5)


Покопавшись в куче методов, я нашел этот вопрос по SO, который помог мне понять, как связать одиночные методы слушателей.

Вот что делать с RadioGroup:

В слушателе RadioGroup у вас есть метод onCheckedChanged(RadioGroup g, int id). Таким образом, вы можете напрямую привязать этот метод к своему обработчику или своей активности, передав его экземпляр в качестве переменной в файле макета и вызвав метод с той же сигнатурой.

Поэтому вызовите файл макета следующим образом:

  <RadioGroup
        android:id="@+id/split_type_radio"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:checkedButton="@+id/split_type_equal"
        android:gravity="center"
        android:onCheckedChanged="@{handler.onSplitTypeChanged}"
        android:orientation="horizontal">

       ...

   </RadioGroup>

И в моей активности или обработчике мне нужно просто предоставить метод с тем же именем и подписью, как здесь:

public void onSplitTypeChanged(RadioGroup radioGroup,int id) {
  // ...
}

Просто убедитесь, что метод общедоступен.

ПРИМЕЧАНИЕ. Это работает для любых (большинство, я не пробовал все) методов слушателя. Например, для EditText вы можете предоставить android:onTextChanged и так далее.

person kirtan403    schedule 11.09.2016
comment
Когда я пытаюсь использовать android:onCheckedChanged в моем xml, он говорит неизвестный атрибут, мне удалось заставить привязку данных работать с прослушивателем кликов, но это же решение не работает для меня - person Jude Fernandes; 13.01.2017
comment
@JudeFernandes В настоящее время в студии Android есть некоторые ошибки в lint, но они отлично компилируются и работают. Просто игнорируйте предупреждение. Можете ли вы объяснить немного больше о вашей проблеме? - person kirtan403; 17.01.2017
comment
как справиться с двусторонней ручкой с помощью этого подхода? - person droidev; 13.09.2017
comment
что, если я хочу имя этого проверенного переключателя. ? - person Ravi Vaniya; 03.10.2017
comment
@RayVaniya У вас есть экземпляр радиогруппы. Получите это от этой радиогруппы - person kirtan403; 04.10.2017

Я использую строку, и в этом случае у меня есть привязка на основе viewModel.getCommuteType() viewModel.setCommuteType(String)

<RadioGroup
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.DRIVING)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.DRIVING)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="D"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.BICYCLE)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.BICYCLE)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="B"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.WALKING)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.WALKING)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="W"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.BUS)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.BUS)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="T"/>

person Juan Mendez    schedule 07.10.2017
comment
как его валидировать? это проверено или нет - person EL TEGANI MOHAMED HAMAD GABIR; 03.08.2019
comment
checkout LiveData.Transformations, чтобы извлечь выгоду из просмотра других LiveData, таких как случай моего viewMdodel.commuteType, таким образом вы можете определить LiveData<Boolean>, наблюдающий за viewModel.commuteType, изначально имеющий Commute.NONE, который дает false, и если он имеет какое-либо другое значение, то это правда. proandroiddev.com/ - person Juan Mendez; 04.08.2019
comment
в любое время брат. надеюсь, что помог вам. - person Juan Mendez; 06.08.2019
comment
использовал это решение с MediatorLiveData, оно работало безупречно. - person sud007; 02.02.2021
comment
@sud007очень приятно слышать! - person Juan Mendez; 03.02.2021

Через несколько часов я нашел простой способ: двусторонняя привязка данных в android. Это базовый скелет с livedata и Kotlin. Также вы можете использовать ObservableField()

  1. Настройте viewmodel на данные
  2. Создайте свою радиогруппу с нужными вам кнопками. Важно: установить всем радиокнопкам id!!!
  3. Установите в своей радиогруппе двустороннюю binding для проверки переменная (используйте переменную модели представления)
  4. Наслаждаться)

макет.xml

<data>
    <variable
        name="VM"
        type="...YourViewModel" />
</data>


<LinearLayout
            android:id="@+id/settings_block_env"
            ...
            >


            <RadioGroup

                android:id="@+id/env_radioGroup"
                android:checkedButton="@={VM.radio_checked}">

                <RadioButton
                    android:id="@+id/your_id1"/>

                <RadioButton
                   android:id="@+id/your_id2" />

                <RadioButton
                    android:id="@+id/your_id3"/>

                <RadioButton
                    android:id="@+id/your_id4"/>
            </RadioGroup>

        </LinearLayout>

class YourViewModel(): ViewModel {

var radio_checked = MutableLiveData<Int>()


init{
    radio_checked.postValue(R.id.your_id1)//def value
}

//other code
}
person Serega Maleev    schedule 18.01.2019
comment
Это самое простое решение с двусторонней привязкой данных. И вы можете использовать значение по умолчанию в качестве параметра конструктора MutableLiveData(R.id.your_id1) - person Stanislav Bondar; 29.07.2019
comment
Конечно, это является. Также вместо var следует использовать val. - person Serega Maleev; 30.07.2019
comment
что мне делать с radio_checked.postValue(R.id.your_id1), если их несколько, я хочу их проверить, например, если у меня есть два переключателя, мужчина и женщина, я хочу сделать проверку на check@StanislavBondar - person EL TEGANI MOHAMED HAMAD GABIR; 01.08.2019
comment
@ELTEGANIMOHAMED Я не уверен, но вы должны установить наблюдателей для всех LiveData и вызвать метод yourValidate(). Или создайте другой isValid: LiveData‹Boolean›. - person Serega Maleev; 02.08.2019
comment
@SeregaMaleev radio_checked.postValue(R.id.your_id1)//def value как бы вы определили, какая RadioButton была нажата? и как мы можем вернуть значение переключателя, выбранного пользователем? - person GeekDroid; 24.12.2019
comment
Android: проверенная кнопка - person Serega Maleev; 27.12.2019
comment
@Cosmic Dev Вам нужно установить наблюдателя в свой фрагмент или активность. - person Serega Maleev; 12.06.2020

Часто вас больше волнует что действительно было проверено, а не "что-то было проверено". В таком случае альтернативным решением является игнорирование RadioGroup и привязка всех элементов, как показано ниже:

<RadioGroup (...) >
        <RadioButton (...)
            android:checked="@={viewModel.optionA}"/>

        <RadioButton (...)
            android:checked="@={viewModel.optionB}"/>

        <RadioButton (...)
            android:checked="@={viewModel.optionC}"/>
</RadioGroup>

где optionA, optionB и optionC определены в ViewModel, как показано ниже:

public final ObservableBoolean optionA = new ObservableBoolean();
public final ObservableBoolean optionB = new ObservableBoolean();
public final ObservableBoolean optionC = new ObservableBoolean();

Обычно этого достаточно, однако, если вы хотите немедленно реагировать на щелчок, вы можете добавить обратные вызовы и использовать их следующим образом:

OnPropertyChangedCallback userChoosedA = new OnPropertyChangedCallback() {
    @Override
    public void onPropertyChanged(Observable sender, int propertyId) {
        (...) // basically propertyId can be ignored in such case
    }
};

optionA.addOnPropertyChangedCallback(userChoosedA);

Преимущество такого подхода в том, что вам не нужно сравнивать и отслеживать «id».

person LLL    schedule 20.12.2017

В моем текущем проекте я сделал это так. У меня в проекте три валюты и я выбираю одну из них через RadioGroup.

Это перечисление с валютами:

enum class Currency(val value: Byte) {
    USD(0),
    EUR(1),
    RUB(2);

    companion object Create {
        fun from(sourceValue: Byte): Currency = values().first { it.value == sourceValue }
        fun from(sourceValue: String): Currency = values().first { it.toString() == sourceValue }
    }
}

Часть моей ViewModel:

    class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
        /**
         * Selected currency
         */
        val currency: MutableLiveData<Currency> = MutableLiveData()

        /**
         *
         */
        init {
            currency.value = Currency.USD   // Init value
        }
  }

Часть моего макета (обратите внимание на привязку в RadioGroup и теги RadioButton):

<RadioGroup
    android:id="@+id/currencySwitchers"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    app:selectedCurrency = "@{viewModel.currency}"

    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintEnd_toEndOf="parent">

    <RadioButton
        android:id="@+id/usdSwitcher"

        android:text="USD"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="USD"
    />

    <RadioButton
        android:id="@+id/eurSwitcher"

        android:text="EUR"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="EUR"
    />

    <RadioButton
        android:id="@+id/rubSwitcher"

        android:text="RUB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="RUB"
    />
</RadioGroup>

И завершающая часть — обвязка переходника.

@BindingAdapter("selectedCurrency")
fun setSelectedCurrency(view: View, value: MutableLiveData<Currency>?) {
    view.getParentActivity()?.let { parentActivity ->
        value?.observe(parentActivity, Observer { value ->
            view.findViewWithTag<RadioButton>(value.toString())
                ?.also {
                    if(!it.isChecked) {
                        it.isChecked = true
                    }
                }
            }
        )

        (view as RadioGroup).setOnCheckedChangeListener { radioGroup, checkedId ->
            val currency = Currency.from(radioGroup.findViewById<RadioButton>(checkedId).tag as String)
            if(value != null && value.value != currency) {
                value.value = currency
            }
        }
    }
}

Таким образом, я получил двустороннюю привязку между RadioGroup и свойством в моей ViewModel.

person Alex Shevelev    schedule 12.01.2019
comment
у вас есть свой код в android - java, а не в котлине? - person batsheva; 09.06.2020
comment
@batsheva Нет, извините. Я не использую Java в последнее время. - person Alex Shevelev; 10.06.2020
comment
@AlexShevelev Спасибо ... за решение - person BarmanInfo; 08.07.2020