web-dev-qa-db-ja.com

android databinding:プログラムでトリガーされるonCheckedChangedを回避する方法

Androidデータバインディングをプロジェクトで使用しようとしていますが、この種の問題が発生します。たとえば、チェックボックスグループとして3つのチェックボックスがあります。最初のチェックボックスがオンの場合、次に変数typeは1です。2番目はtypeを2にし、3番目はtypeを3にします。このようにコードを実装します。

_   // 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);
    }
}
_

問題は、1番目のチェックボックスをオンにした場合、2番目のチェックボックスをオンにすることです。 typeを2に設定し、UIを正しく更新する必要があります。しかし実際には、uncheckイベントも最初のチェックボックスで発生し、typeが2に設定された後、type.set(0)がトリガーされるため、チェックボックスはチェックされません。

実際、この問題は onCheckedChangedが自動的に呼び出される と同じです。私が必要としているのは、データバインディングのソリューションです。

非データバインディングプロジェクトでは、setCheckedSilent(@ Emanuel Andradaによる回答)を使用するのが最善の解決策だと思います。

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

しかし、データバインディングでは、これを行うことはできません。それで、私を助けることができる専門家はいますか?

@Arpan Sharmaの回答によると、onClickではなくonCheckedChangedを聞いてください。このソリューションは現在機能していますが、checkedの値が心配です。常に正しいですか?

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

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

私は同じ問題に直面し、onCHeckリスナーではなくonCLickリスナーを使用しました。このようにして、プログラムで設定されたときにリスナーがチェック状態を変更しません。あなたの問題では、チェックボックスに異なるチェック変更リスナーを設定してみてください。

5
Arpan Sharma

これはデータバインディングで非常に簡単です

XMLチェックボックスコンポーネント

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

ViewModelまたはアクティビティ内

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

チェックがオンの場合はブールチェックtrue、オフの場合はfalse

3
Atul

私はこの質問に初めて遭遇し、バインディングアダプターを使用して実装する方が良いと思います。

アダプタをバインドするためのコードは次のとおりです

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

そして、どの複合ボタンでも使用できます

<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

ViewModelからObservableBooleanを公開し、そのブールに対して双方向のデータバインディングを使用します。

次に、ObservableBooleanの値を使用して、XMLにエンコードするのではなく、何を実行するかを決定できます。

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

双方向のバインドを防ぐために、onClickの代わりにonCheckedChangedを使用します。

From 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" />

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