web-dev-qa-db-ja.com

Android XMLを使用したスピナーデータバインディングと選択した値の表示

私は新しいAndroidデータバインディングを使用しています。これは素晴らしい動作です。EditText、TextView、Radio、およびチェックボックスを使用してデータバインディングを実行できます。 。

以下のリンクでいくつかの手がかりを見つけました: XMLレイアウトを使用したAndroidスピナーデータバインディング

しかし、まだ解決策を見つけることができません。また、双方向のデータバインディングを実行する必要があります。スピナーデータの選択値を反映する必要があります。

誰かが例を教えてくれますか?

これが私のxmlコードです:

<layout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/tools"
    xmlns:card_view="http://schemas.Android.com/apk/res-auto">

    <data>
        <import type="Android.view.View" />
        <variable
            name="viewModel"
            type="com.ViewModels.model" />
    </data>

     <Spinner
                    Android:id="@+id/assessmemt_spinner"
                    Android:layout_width="match_parent"
                    Android:layout_height="wrap_content"
                    Android:layout_alignParentRight="true"
                    Android:layout_margin="@dimen/carview_margin"
                    Android:layout_toRightOf="@+id/text_bp"
                    Android:drawSelectorOnTop="true"
                    Android:spinnerMode="dropdown"
                   Android:visibility="@{viewModel.type.equals(@string/spinner_type)?  View.VISIBLE : View.GONE}" />
</layout>

モデルを表示:

 public class AssessmentGetViewModel {
    private String valueWidth;
    private ArrayList<String> values;
    private String type;
    public String getValueWidth() { return this.valueWidth; }
    public void setValueWidth(String valueWidth) { this.valueWidth = valueWidth; }
    public ArrayList<String> getvalues() { return this.values; }
    public void setvalues(ArrayList<String> values) { this.values = values; }
    public String gettype() { return this.type; }
    public void settype(String type) { this.type = type; }
    }
28
San Jaisy

私は何かが役に立つかもしれないと思ったが、双方向データバインディングの公式文書にはない。

1。双方向データバインディングの「@ =」の使用法

2。これを実現するには、双方向のカスタムデータバインディングに「BindingAdapter」および「InverseBindingAdapter」アノテーションが必要です。

最初の項目では、多くのブロガーが双方向のデータバインディングで「@ =」を使用することを示しました。 https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-Android/

2番目の項目については、@ George Moundがここで返信したように( edittextのデフォルトテキストがfloat値の場合、テキストカーソルが左にリセットされます )EditBindingは、「BindingAdapter」と「 InverseBindingAdapter」アノテーション。

指示に従って、スピナーの双方向バインディング方法を構築できます。

まず、ViewModelを作成するか、Pojoを使用します

ViewModel

public class ViewModel {
    private ObservableField<String> text;
    public ViewModel() {
        text = new ObservableField<>();
    }
    public ObservableField<String> getText() {
        return text;
    }
}

ポジョ

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

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

次に、xmlに追加します。

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

}

あなたが見たように、デフォルトの選択値の変数として「selectedValue」を使用しましたが、「selectedValueAttrChanged」とは何ですか?私はこれがトリッキーだと思いました(呼び出されたときにnullではない理由はわかりません)、それはxmlに追加する必要はありませんスピナーで変更されたアイテムをリッスンするためのコールバックのみです。そして、onItemSelectedListenerを設定し、InverseBindingListeneronchange()関数を呼び出すように設定します(ドキュメントと例はこちら: https:// developer。 Android.com/reference/Android/databinding/InverseBindingAdapter.htmlデフォルトのイベントは「Android:textAttrChanged」であり、カスタム双方向バインド逆バインドを使用する場合は、接尾辞が「AttrChanged」の属性を使用する必要があります

イベントのデフォルト値は、「AttrChanged」という接尾辞が付いた属性名です。上記の例では、デフォルト値は提供されなくてもAndroid:textAttrChangedでした。

最後に、アクティビティとstring.xmlで

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding lBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_main, null, false);
    mViewModel = new ViewModel();
    mViewModel.getText().set("Wednesday");
    lBinding.setViewModel(mViewModel);
    lBinding.setHandler(new Handler());
    setContentView(lBinding.getRoot());
}

string.xml

<array name="days">
    <item name="Mon">Monday</item>
    <item name="Tue">Tuesday</item>
    <item name="Wed">Wednesday</item>
</array>

コードを実行すると、スピナーのデフォルト値として「水曜日」が表示されます。これが多くの人々に役立つことを願っています

27
Long Ranger

OnItemSelectedを使用して簡単に実行し、選択した位置と選択したアイテムテキストを取得できます。

1)以下のようにスピナーにonItemSelected属性を追加します。

<Spinner
      Android:id="@+id/spinner"
      Android:layout_width="match_parent"
      Android:layout_height="wrap_content"
      Android:entries="@array/item_list"
      Android:onItemSelected="@{(parent,view,pos,id)->viewModel.onSelectItem(parent,view,pos,id)}"/>

2)次に、このメソッドをviewModelに追加する必要があります。

public void onSelectItem(AdapterView<?> parent, View view, int pos, long id)
{
    //pos                                 get selected item position
    //view.getText()                      get lable of selected item
    //parent.getAdapter().getItem(pos)    get item by pos
    //parent.getAdapter().getCount()      get item count
    //parent.getCount()                   get item count
    //parent.getSelectedItem()            get selected item
    //and other...
}

配列はvalues/item_list.xmlに保存する必要があるこのようなものになります。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="item_list">
        <item>item1</item>
        <item>item2</item>
        <item>item3</item>
    </array>
</resources>

レイアウトが描画されると、onItemSelectedが呼び出され、初期値を設定できます。

parent.setSelection(1); //1 is position of initializing value
19

1行のソリューション

_Android:selectedItemPosition="@={item.selectedItemPosition}"_

それだけです!カスタムBindingAdapterを作成する必要はありません。

Spinnerは、属性selectionおよびselectedItemPositionによる双方向バインディングを既にサポートしています。 Androidドキュメントを参照

スピナーの変更がモデルフィールドに反映されるように、双方向バインディングselectedItemPositionを使用する必要があります。

Item.class

_public class Item extends BaseObservable {
    private int selectedItemPosition;

    @Bindable
    public int getSelectedItemPosition() {
        return selectedItemPosition;
    }

    public void setSelectedItemPosition(int selectedItemPosition) {
        this.selectedItemPosition = selectedItemPosition;
        notifyPropertyChanged(BR.selectedItemPosition);
    }
}
_

activity_main.xml

_<variable
    name="item"
    type="com.sample.data.Item"/>

<Android.support.v7.widget.AppCompatSpinner
    ...
    Android:entries="@array/items"
    Android:selectedItemPosition="@={item.selectedItemPosition}"
    >
_

MainActivity.Java

_public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setItem(new Item());
        binding.getItem().setSelectedItemPosition(4); // this will change spinner selection.
        System.out.println(getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]);
    }
}
_

コードから選択したアイテムをいつでも取得する必要がある場合は、これを使用します

_binding.getItem().getSelectedItemPosition(); // get selected position
getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]) // get selected item
_

プログラムで変更する必要がある場合は、変数@ Bindableを作成します。

_binding.getItem().setSelectedItemPosition(4);
_

それ以外の場合は、@ BindableおよびnotifyPropertyChanged(BR.selectedItemPosition);を削除できます。

BaseObservableまたはObservableFieldまたは-のいずれかを使用できます ライブデータ。それはあなた次第です。 私は BaseObservable を使用します。これは非常に単純だからです。、BaseObservableから拡張するだけで、すべてのフィールドが観察可能になりました。

13
Khemraj

my answer を参照して、スピナーで最も簡単なデータバインディングを達成してください。実際、さらなるタスクを実行するにはアダプターが必要です。

XMLコードがあります。

Java:


    //  Data binding
        ActivityParentsRegBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_parents_reg);
        binding.setCities(ConstData.getCitiesList());
0
ForWebTech

1-classを1つ作成して場所に名前を付け、コードをクラスに設定する例

public class Location {

    private int Id;
    private String Title;

    public Location(int Id,String Title){
        this.Id=Id;
        this.Title=Title;
    }

    public int getId() {
        return Id;
    }

    public void setId(int id) {
        Id = id;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        Title = title;
    }

    @Override
    public String toString() {
        return Title;
    }
}

2-Spinnerを1つ作成し、このコードをJavaに書き込む

Spinner cmb_Area = view.findViewById(R.id.Fragment_Add_Home_cmb_Area);

ArrayList<Location> locations= new ArrayList<>();

locations.add(new Location(1,"London"));
locations.add(new Location(2,"Paris"));

ArrayAdapter<Location> adapter2 = new ArrayAdapter<Location>(getActivity(), Android.R.layout.simple_spinner_dropdown_item, locations);

cmb_Area.setAdapter(adapter2);

3-このコードを書いてアイテムを選択する

cmb_Area.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        Location location = (Location) parent.getSelectedItem();
        Toast.makeText(getActivity(),location.getId(),Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});
0
Diako Hasani

@ロングレンジャー私はあなたの答えが本当に好きですが、ループを破るために私たちがしなければならないことがあると思います。このように:

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