How to bind method on RadioGroup on checkChanged event with data-binding

前端 未结 5 1706
甜味超标
甜味超标 2021-01-31 09:32

I was searching over the internet for how to perform the new cool android data-binding over the RadioGroup and I didn\'t find a single blog post about it.

相关标签:
5条回答
  • 2021-01-31 09:44

    I am using a string, and in this case I have bindable based on 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"/>
    

    0 讨论(0)
  • 2021-01-31 09:45

    After some hours I found easy way: two-way databinding in android. It's base skeleton with livedata and Kotlin. Also you can use ObservableField()

    1. Set your viewmodel to data
    2. Create your radiogroup with buttons as you like. Important: set all radio buttons id !!!
    3. Set in your radio group two-way binding to checked variable (use viewmodel variable)
    4. Enjoy)

    layout.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
    }
    
    0 讨论(0)
  • 2021-01-31 09:51

    After digging to the bunch of methods, I found this question on SO which helped me understand how to bind single methods of listeners.

    Here is what to do with RadioGroup:

    In RadioGroup listener you have a method onCheckedChanged(RadioGroup g, int id). So you can directly bound that method to your handler or your activity by passing an instance of it as a variable in layout file and calling a method with the same signature.

    So call on layout file like this:

      <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>
    

    And in my activity or handler, I need to simply provide the method with same name and signature like this:

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

    Just make sure method is public.

    NOTE: This works for any (most of, I have not tried all) listener methods. Like for EditText you can provide android:onTextChanged and so on.

    0 讨论(0)
  • 2021-01-31 10:04

    Often you care more about what was actually checked instead of "something was checked". In such case alternative solution is to ignore RadioGroup and bind all items as below:

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

    where optionA, optionB and optionC are defined in ViewModel like below:

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

    This is usually enough, however if you want to react immediately on click then you can add callBacks and use them like that:

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

    Advantage of such approach is that you don't need to compare and track "id".

    0 讨论(0)
  • 2021-01-31 10:09

    In my current project, I did it like this. I have three currency in the project and I choose one of them via RadioGroup.

    It's enum with currencies:

    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 }
        }
    }
    

    A piece of my ViewModel:

        class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
            /**
             * Selected currency
             */
            val currency: MutableLiveData<Currency> = MutableLiveData()
    
            /**
             *
             */
            init {
                currency.value = Currency.USD   // Init value
            }
      }
    

    Part of my layout (pay attention to binding in RadioGroup and tags of 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>
    

    And the final part - binding adapter.

    @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
                }
            }
        }
    }
    

    In this way, I got two-way binding between RadioGroup and a property in my ViewModel.

    0 讨论(0)
提交回复
热议问题