Связывание данных Android - не удается найти получатель для атрибута - PullRequest
0 голосов
/ 14 мая 2018

Я использовал некоторую привязку блесны после просмотра в этого ответа .Но я не могу скомпилировать код после этого.

Ошибка

Обнаружены ошибки привязки данных.**** / ошибка привязки данных **** msg: не удается найти получатель для атрибута selectedValue с типом значения java.lang.String для android.widget.Spinner.file: D: \ Khemraj_AndroidStudioWorkspace_ \ amelioFinal \ app \ src \ main \ res \ layout \ activity_cart.xml loc: 167: 24 - 175: 33 **** \ ошибка привязки данных ****

Pojo

public class ViewModel {
    private String text;
    public String getText() {
        return text;
    }

    public void setText(String text)
    {
       this.text = text;
    }
}

в формате xml

  <variable
        name="viewModel"
        type="com.amelio.model.ViewModel"/>

и

  <android.support.v7.widget.AppCompatSpinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/days"
            bind:selectedValue="@={viewModel.text}"/>

bindingUtil

public class SpinnerBindingUtil {

    @BindingAdapter(value = {"selectedValue", "selectedValueAttrChanged"}, requireAll = false)
    public static void bindSpinnerData(AppCompatSpinner pAppCompatSpinner, String newSelectedValue, final InverseBindingListener newTextAttrChanged) {
        pAppCompatSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                newTextAttrChanged.onChange();
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
        if (newSelectedValue != null) {
            int pos = ((ArrayAdapter<String>) pAppCompatSpinner.getAdapter()).getPosition(newSelectedValue);
            pAppCompatSpinner.setSelection(pos, true);
        }
    }
    @InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
    public static String captureSelectedValue(AppCompatSpinner pAppCompatSpinner) {
        return (String) pAppCompatSpinner.getSelectedItem();
    }

}

1 Ответ

0 голосов
/ 14 мая 2018

Существует атрибут android:selectedItemPosition, который поддерживает двустороннюю привязку данных из коробки. Вы можете использовать это или использовать BindingAdapter / InverseBindingAdapter пару в качестве шаблона:

@InverseBindingMethods({
    @InverseBindingMethod(type = AdapterView.class, attribute = "android:selectedItemPosition"),
    @InverseBindingMethod(type = AdapterView.class, attribute = "android:selection",
            method = "getSelectedItemPosition",
            event = "android:selectedItemPositionAttrChanged"),
})

...

@BindingAdapter("android:selectedItemPosition")
public static void setSelectedItemPosition(AdapterView view, int position) {
    if (view.getSelectedItemPosition() != position) {
        view.setSelection(position);
    }
}

@BindingAdapter(value = {"android:onItemSelected", "android:onNothingSelected",
        "android:selectedItemPositionAttrChanged" }, requireAll = false)
public static void setOnItemSelectedListener(AdapterView view, final OnItemSelected selected,
        final OnNothingSelected nothingSelected, final InverseBindingListener attrChanged) {
    if (selected == null && nothingSelected == null && attrChanged == null) {
        view.setOnItemSelectedListener(null);
    } else {
        view.setOnItemSelectedListener(
                new OnItemSelectedComponentListener(selected, nothingSelected, attrChanged));
    }
}

Это заставило бы меня сделать что-то вроде этого:

@InverseBindingMethods({
    @InverseBindingMethod(type = AdapterView.class,
                          attribute = "android:selectedValue",
                          method = "getSelectedItem"
})
public class SelectedValueBindingAdapter {
    @BindingAdapter("android:selectedValueAttrChanged")
    public static void setSelectedValueListener(AdapterView view,
            final InverseBindingListener attrChanged) {
        if (attrChanged == null) {
            view.setOnItemSelectedListener(null);
        } else {
            view.setOnItemSelectedListener(new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    attrChanged.onChange();
                }
                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                    attrChanged.onChange();
                }
            });
        }
    }

    @BindingAdapter("android:selectedValue")
    public static void setSelectedValue(AdapterView<?> view, Object selectedValue) {
        Adapter adapter = view.getAdapter();
        if (adapter == null) {
            return;
        }
        // I haven't tried this, but maybe setting invalid position will
        // clear the selection?
        int position = AdapterView.INVALID_POSITION;

        for (int i = 0; i < adapter.getCount(); i++) {
            if (adapter.getItem(i) == selectedValue) {
                position = i;
                break;
            }
        }
        view.setSelection(position);
    }
}
...