web-dev-qa-db-fra.com

android liaison de données: comment éviter que onCheckedChanged ne soit déclenché par programmation

J'essaie maintenant d'utiliser Android liaison de données dans mon projet et je rencontre ce type de problème, par exemple: j'ai 3 cases à cocher en tant que groupe de cases à cocher, si la première case à cocher est cochée, puis un la variable type est 1. la seconde fait type à 2, la troisième fait type à 3. donc j'implémente le code de cette façon.

   // layout.xml


   <Android.support.v7.widget.AppCompatCheckBox
        Android:layout_width="50dp"
        Android:layout_height="50dp"
        Android:checked="@{userInfoViewModel.type == 1}"
        Android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 1)}"
        />

   <Android.support.v7.widget.AppCompatCheckBox
        Android:layout_width="50dp"
        Android:layout_height="55dp"
        Android:checked="@{userInfoViewModel.type == 2}"
        Android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 2)}"
        />

    <Android.support.v7.widget.AppCompatCheckBox
        Android:layout_width="50dp"
        Android:layout_height="55dp"
        Android:checked="@{userInfoViewModel.type == 3}"
        Android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 3)}"
        />

// viewModel

public void onTypeChecked(boolean checked, int i) {
    if (checked) {
        // if it is a check. set the type
        type.set(i);
    } else {
        // if it is a uncheck. set type to unknown
        type.set(0);
    }
}

Maintenant, le problème est que, si j'ai coché la 1ère case, alors je coche la 2e. type doit être défini sur 2 et l'interface utilisateur doit être mise à jour correctement. Mais la réalité est que l'événement uncheck se produit également sur la 1ère case à cocher, après que type est défini sur 2, puis type.set(0) est déclenchée, donc aucune case n'est cochée.

En fait, ce problème est identique à onCheckedChanged appelé automatiquement . J'ai besoin d'une solution pour la liaison de données.

Dans un projet sans liaison de données, je pense que la meilleure solution est d'utiliser setCheckedSilent (réponse de @Emanuel Andrada).

  public void setCheckedSilent(boolean checked) {
    super.setOnCheckedChangeListener(null);
    super.setChecked(checked);
    super.setOnCheckedChangeListener(listener);
}

Mais en liaison de données, je ne peux pas faire ça. Y a-t-il un expert qui peut m'aider?

Selon la réponse de @Arpan Sharma, écoutez onClick au lieu de onCheckedChanged. Cette solution fonctionne actuellement, mais je m'inquiète de la valeur de checked, est-ce toujours le cas?

public void onTypeChecked(View view, int i) {
    Boolean checked = ((CheckBox) view).isChecked();

    if (checked) {
        type.set(i);
    } else {
        type.set(0);
    }
}
12
Leon

J'ai rencontré le même problème et j'ai utilisé l'écouteur onCLick à la place de l'écouteur onCHeck. De cette façon, l'auditeur ne changera pas l'état de vérification lorsqu'il est défini par programme. Dans votre problème, vous devez essayer de définir différents écouteurs de changement de vérification dans vos cases à cocher.

5
Arpan Sharma

C'est très simple avec la liaison de données

Dans le composant de case à cocher XML

 <CheckBox
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:onCheckedChanged="@{(compoundButton, checked) -> 
changeKeyboardVM.onCheckedChange(compoundButton, checked)}" />

Dans ViewModel ou Activity

  public void onCheckedChange(CompoundButton button, boolean check) {
    Log.d("Z1D1", "onCheckedChange: " + check);
}

maintenant vérification booléenne true sur cochée et false sur non cochée

3
Atul

Je suis tombé sur cette question pour la première fois et je pense qu'il vaut mieux être implémenté à l'aide d'un adaptateur de liaison.

Voici le code pour l'adaptateur de liaison

interface OnUserCheckedChangeListener {
    fun onUserCheckChange(view:CompoundButton, isChecked:Boolean)
}
@BindingAdapter("onUserCheckedChange")
fun setUserCheckedChangeListener(view:CompoundButton, listener: OnUserCheckedChangeListener?){
    if(listener == null){
        view.setOnClickListener(null)
    }else{
        view.setOnClickListener {
            listener.onUserCheckChange(view, view.isChecked)
        }
    }
}

Et nous pouvons l'utiliser sur n'importe quel bouton composé

<CheckBox
            Android:id="@+id/finish_check"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"   
            Android:checked="@{your_condition}"
            onUserCheckedChange="@{(view, checked) -> vm.onItemChecked(todo, checked)}"
            />
2
Debanjan

Exposez un ObservableBoolean à partir du ViewModel, puis utilisez la liaison de données bidirectionnelle sur ce booléen.

Ensuite, vous pouvez utiliser les valeurs de l'ObservableBoolean pour décider ce que vous voulez faire, plutôt que de le coder dans le XML.

Android:checked="@={vm.checkedValue}"
0
EpicPandaForce

Utilisation de onClick au lieu de onCheckedChanged pour empêcher la liaison bidirectionnelle.

De item_order_view.xml:

<data>

    <variable
        name="viewModel"
        type="com.package.name.OrderItemViewModel" />
</data>

           <CheckBox
                Android:id="@+id/cb_selected"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:layout_marginLeft="8dp"
                Android:buttonTint="@color/white"
                Android:checked="@{viewModel.isSelect}"
                Android:onClick="@{() -> viewModel.onClickedCheckBox()}"
                Android:textColor="@color/white" />

De OrderItemViewModel.Java

public class OrderItemViewModel {

    public final ObservableField<Boolean> isSelect;
    public final OrderItemViewModelListener mListener;
    private final Order mOrder;

    public OrderItemViewModel(Order order, OrderItemViewModelListener listener) {
        this.mListener = listener;
        this.mOrder = order;

        isSelect = new ObservableField<>(mOrder != null ? mOrder.isSelect() : false);
    }

    /**
     * Using onClick instead of onCheckedChanged
     * to prevent 2-ways binding issue.
     */
    public void onClickedCheckBox() {
        mListener.onCheckChanged();
    }

    public interface OrderItemViewModelListener {
        void onCheckChanged();
    } 
}
0
Tri Ngo Minh