アンドリュースデータバインディング(5)カスタムビューの道結合

Androidのデータバインド()基本的な使い方 
Androidのデータバインディング(2)イベントハンドラ 
Androidのデータバインディング(3)観測可能な 
Androidのデータバインド(d)のカスタム属性 
のAndroidデータバインディング(5)双方向結合(紙)のカスタムビュー 
Androidのデータバインディング(6)のEditTextネクタイTextChangedListenerとFocusChangeListener与えられました

序文

あなたは双方向の結合を達成する必要がある場合は、時間の使用非システム定義のプロパティ場合は、カスタムビューは、@ =行で、カスタムビューにもいくつかの設定を必要としません。

次の例では、結合双方向を実現するカスタムビューを介して説明します。

例は、請求項: 
1.ラジオボタンは、(食べる/スリープ/プレイエンドウ豆趣味オプションである)趣味を選択し 
、表示画面2をロードするときに初期値が(ラジオボタンへのViewModel広がり式設定値)に関心がある 
3。 ViewModelにに渡された値際のRadioButtonは、選択 
4.ラジオボタンの値を空にすることができ、あなたが情熱を持っていないことを意味しています、

最初のカスタムのRadioButtonとRADIOGROUP

趣味は、列挙型を定義する必要があり、idでラジオボタンRADIOGROUP時間を選択するように来る、それは第一の結合を達成することができる列挙IDに変換されなければなりません。しかし、我々は彼らが結合列挙型をサポートできるようにするためのRadioButtonとRADIOGROUPをカスタマイズすることができます!

カスタムコードのRadioButtonを初めて目

public class DataBindingRadioButton extends AppCompatRadioButton {

    private Integer value;

    public DataBindingRadioButton(Context context) {
        super(context);
    }

    public DataBindingRadioButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DataBindingRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    @Override
    public void toggle() {
        if (isChecked()) {
            if (getParent() instanceof RadioGroup) {
                // 点击选中的 RadioButton,可以取消选择
                ((RadioGroup) getParent()).clearCheck();
            }
        } else {
            setChecked(true);
        }
    }

    @BindingAdapter(value = {"value"})
    public static void setValue(DataBindingRadioButton radioButton, Integer value) {
        radioButton.setValue(value);
        ViewParent parent = radioButton.getParent();
        if (parent instanceof DataBindingRadioGroup) {
            Integer checkedValue = ((DataBindingRadioGroup) parent).getCheckedValue();
            radioButton.setChecked(IntegerUtil.isSame(checkedValue, value));
        }
    }
}

私たちは、値が列挙値の整数に対応する値であり、プロパティ値を定義しDataBindingRadioButtonを与えます。

列挙値は、結合データバインディングを介して来て、対応する方法を設定する必要があります。

私たちは、setValueの(整数値)が、@BindingAdapterで使用していませんでした 
さらにDataBindingRadioButtonのパラメータで設定方法を使用して。

理由だけではなく、ラジオボタンを選択された1知るRADIOGROUPの必要性を聞かせて、渡された値です。RADIOGROUPもしOnCheckedChangeはその後、radioButton.setCheckedはRADIOGROUPを通知します、耳を傾けます。

ラジオボタンが選択されていないをサポートするためにあるコードのどの部分トグル()のRadioButton、デフォルトを選択する必要があります。私たちの要求ため、または趣味を持っていないかもしれません。

書かれた2つの整数クラスUtilのを比較するためのコードIntegerUtil。質問は、なぜは整数型の値の値ではなく、intですか?それサポートは愛を選択しないので、Integer型を定義する必要があるので、そう愛する値は、nullにすることができます。

以下は、カスタムコードRADIOGROUPです

@InverseBindingMethods({
        @InverseBindingMethod(
                type = DataBindingRadioGroup.class,
                attribute = "checkedValue",
                event = "checkedValueAttrChanged",
                method = "getCheckedValue")
})
public class DataBindingRadioGroup extends RadioGroup {

    private Integer checkedValue;
    private OnValueChangedListener listener;

    public DataBindingRadioGroup(Context context) {
        super(context);
        init();
    }

    public DataBindingRadioGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void init() {
        setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId > 0) {
                DataBindingRadioButton radioButton = (DataBindingRadioButton) findViewById(checkedId);
                setCheckedValue(radioButton.isChecked() ? radioButton.getValue() : null);
            } else {
                setCheckedValue(null);
            }
        });
    }

    public Integer getCheckedValue() {
        return checkedValue;
    }

    public void setCheckedValue(Integer checkedValue) {

        if (IntegerUtil.isSame(this.checkedValue, checkedValue)) {
            return;
        }

        this.checkedValue = checkedValue;

        if (this.checkedValue == null) {
            clearCheck();
        } else {
            DataBindingRadioButton customRadioButton = (DataBindingRadioButton) findViewById(getCheckedRadioButtonId());
            if (customRadioButton == null || !IntegerUtil.isSame(this.checkedValue, customRadioButton.getValue())) {

                for (int i = 0; i < getChildCount(); i++) {
                    View child = getChildAt(i);
                    if (child instanceof DataBindingRadioButton) {
                        Integer value = ((DataBindingRadioButton) child).getValue();
                        if (IntegerUtil.isSame(this.checkedValue, value)) {
                            ((DataBindingRadioButton) child).setChecked(true);
                        }
                    }
                }
            }
        }

        if (listener != null) {
            listener.onValueChanged();
        }
    }

    public void setListener(OnValueChangedListener listener) {
        this.listener = listener;
    }

    public interface OnValueChangedListener {
        void onValueChanged();
    }

    @BindingAdapter("checkedValueAttrChanged")
    public static void setValueChangedListener(DataBindingRadioGroup view, final InverseBindingListener bindingListener) {
        if (bindingListener == null) {
            view.setListener(null);
        } else {
            // 通知 ViewModel
            view.setListener(bindingListener::onChange);
        }
    }
}

逆結合をサポートするには、最初のクラス名に@InverseBindingMethodsを定義する必要があります。 
属性は=「checkedValue」属性は、結合の逆をサポートするために指定されています。 
イベント=「checkedValueAttrChanged」指定されているのvalueChangedイベントをリッスン。 
方法=「getCheckedValue」逆方向データソースの結合方法は、時間を指定。

イベントとメソッドは、指定されていない場合、デフォルトは自動的に次のルールに生成され、必要とされない 
イベント=「xxxAttrChanged」 
メソッド=「のgetXXX」

この方法はまた、上記の工程で直接定義することができます。

@InverseBindingAdapter(attribute = "checkedValue", event = "checkedValueAttrChanged")
public Integer getCheckedValue() {
    return checkedValue;
}

@BindingAdapter(「checkedValueAttrChanged」)は、それがのonChangeメソッドの、InverseBindingListenerに重点を置いて、リスナーメソッドを指定するために使用され、最終的な通知ビューモデル値の変更を配置することである(この例にInverseBindingListenerを生成されたクラスに実装後、ActivityMainBindingは以下、です)実現InverseBindingListenerを貼り付けます。

    private android.databinding.InverseBindingListener mboundView1checkedValueAttrChanged = new android.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            // Inverse of vm.hobby
            //         is vm.setHobby((java.lang.Integer) callbackArg_0)
            // 这里就是 method = "getCheckedValue" 指定的方法
            java.lang.Integer callbackArg_0 = mboundView1.getCheckedValue();
            // localize variables for thread safety
            // vm != null
            boolean vmJavaLangObjectNull = false;
            // vm
            com.teletian.databindingradiobutton.viewmodel.ViewModel vm = mVm;
            // vm.hobby
            java.lang.Integer vmHobby = null;

            vmJavaLangObjectNull = (vm) != (null);
            if (vmJavaLangObjectNull) {
                // 这里就是修改 ViewModel 的值
                vm.setHobby(((java.lang.Integer) (callbackArg_0)));
            }
        }
    };

物事をsetValueChangedListenerのonChangeメソッドが中に入るためにセットをOnValueChangedListener行うことです。

あなたは、私が直接それが直接OKに割り当てられていないInverseBindingListenerの属性の定義を、なぜわざわざ、頼むかもしれません!

はい、それは確かにそうである、上記のコードは本当に簡単にはそうすることができます!あなたが本当にRADIOGROUP OnValueChangedListenerを設定する必要がある場合でも、それはケースにすることはできません!次のコードは、それほど変更する必要があります

    @BindingAdapter(value = {"onCheckedValueChanged", "checkedValueAttrChanged"}, requireAll = false)
    public static void setValueChangedListener(DataBindingRadioGroup view,
                                               final OnValueChangedListener valueChangedListener,
                                               final InverseBindingListener bindingListener) {
        if (bindingListener == null) {
            view.setListener(valueChangedListener);
        } else {
            view.setListener(() -> {
                if (valueChangedListener != null) {
                    valueChangedListener.onValueChanged();
                }
                // 通知 ViewModel
                bindingListener.onChange();
            });
        }
    }

行うにはsetCheckedValueメソッドの内部では制御が状態を確認し、コンテンツのRadioButtonリスニングを行うことです。 
ラジオボタンは、メソッド、setOnCheckedChangeListenerを設定している、その後のinitメソッドをsetChecked、そうsetCheckedValueメソッドが再び呼び出されるコールしているので、サイクル呼び出しを防ぐために、次のコードは必要不可欠です

if (IntegerUtil.isSame(this.checkedValue, checkedValue)) {
    return;
}

RADIOGROUPとラジオボタンは、カスタムレイアウトファイルで見てみましょう、終了します

         <com.teletian.databindingradiobutton.customview.DataBindingRadioGroup
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:checkedValue="@={vm.hobby}">

            <com.teletian.databindingradiobutton.customview.DataBindingRadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="吃饭"
                app:value="@{Hobby.EATING.value}" />

            <com.teletian.databindingradiobutton.customview.DataBindingRadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="睡觉"
                app:value="@{Hobby.SLEEPING.value}" />

            <com.teletian.databindingradiobutton.customview.DataBindingRadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="打豆豆"
                app:value="@{Hobby.ATTACKING_DOUDOU.value}" />

        </com.teletian.databindingradiobutton.customview.DataBindingRadioGroup>

アプリによるラジオボタンの最初の値=「@ {Hobby.EATING.value}」を指定するので入れenum値とラジオボタンの値をリンクアップ。

アプリケーションは、その後RADIOGROUPに配置:checkedValue =「@ = {vm.hobby}」双方向バインディングを設定するために。

ソース

https://github.com/teletian/Android/tree/master/DataBindingRadioButton

公開された24元の記事 ウォンの賞賛5 ビュー20000 +

おすすめ

転載: blog.csdn.net/qq_26923265/article/details/82745515