Two-Way databinding in EditText

后端 未结 6 854
无人共我
无人共我 2020-12-15 06:20

I have this object

ObservableInt someNumber;

public ObservableInt getSomeNumber()
{
    return someNumber;
}

public void setSomeNumber(ObservableInt numbe         


        
相关标签:
6条回答
  • 2020-12-15 06:48

    There is an unpublished trick for simple primitive conversions:

    <android.support.v7.widget.AppCompatEditText
        android:layout_width="0dp"
        android:layout_height="@dimen/agro_item_height"
        android:layout_weight="1"
        android:inputType="numberDecimal"
        android:text="@={`` + myObject.someNumber}"
        android:gravity="center_horizontal"/>
    

    I believe it was only added in Android Studio 2.2.

    0 讨论(0)
  • 2020-12-15 06:51

    Simply do this:

    android:text="@={user.username}"
    

    Full code:

     <EditText
                android:id="@+id/username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="user name"
                android:text="@={user.username}"/>
    

    And User class

    public class User {
    public ObservableField<String> username = new ObservableField<>();
    public ObservableField<String> password = new ObservableField<>();
    
    public User() {
        this("", "");
    }
    
    public User(String username, String password) {
        this.username.set(username);
        this.password.set(password);
    }
    
    0 讨论(0)
  • 2020-12-15 06:56

    Thanks to the binding adapters from @LongRanger I was able to advance a lot more in my solution but I had to make some changes on the adapters and in my code. First of all I had to init the ObservableInt member like this:

    ObservableInt someNumber;
    
    public ObservableInt getSomeNumber()
    {
        return someNumber;
    }
    
    public void setSomeNumber(ObservableInt number)
    {
        this.someNumber = number;
    }
    

    Second, I had to change the adapters given by @LongRanger to be like this:

    @BindingAdapter("android:text")
    public static void bindIntegerInText(AppCompatEditText tv, int value)
    {
        tv.setText(String.valueOf(value));    
    
        // Set the cursor to the end of the text
        tv.setSelection(tv.getText().length());
    }
    
    @InverseBindingAdapter(attribute = "android:text")
    public static int getIntegerFromBinding(TextView view)
    {
        String string = view.getText().toString();
    
        return string.isEmpty() ? 0 : Integer.parseInt(string);
    }
    

    That way I avoid the error: Invalid int "", when trying to do Integer.parse(...) on the @InverseBindingAdapter. After this I had to put the cursor on the end of the EditText with the @BindingAdapter, otherwise the cursor kept moving to the start.

    0 讨论(0)
  • 2020-12-15 06:57

    You can do two-way binding on EditText.

    Using one-way data binding, you can set a value on an attribute and set a listener that reacts to a change in that attribute

    variable is string type

    <android.support.v7.widget.AppCompatEditText
        ...
        android:text="@={model.someString}"
        />
    

    variable is number

    <android.support.v7.widget.AppCompatEditText
        ...
        android:text="@={`` + model.someNumber}"
        />
    

    `` two back apostrophe do binding automatically

    • convert number to string when setting it on EditText
    • convert string text to number when setting in Model

    Tip

    From documentation you can see, two-way binding can be used for many purpose.

    1. CheckBox, RadioButton, Switch, ToggleButton

    android:checked="@={model.checked}"

    1. RadioGroup - android:checkedButton

    android:checkedButton="@={model.selectedId}"

    1. RatingBar - android:rating

    android:rating="@={model.rating}"

    etc.

    0 讨论(0)
  • 2020-12-15 07:03

    I try to use the custom setter as @George Mount mentioned(https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47#.vsry4d95w) , and inspired by this answer (Android two way binding with Integer type causes databinding does not exist)

    You can still use the original code for two-way binding.

    Model class

    public class Age {
        private ObservableInt someNumber;
        private ObservableField<String> someStr;
        public Age() {
            someNumber = new ObservableInt();
            someStr = new ObservableField<>();
        }
        public ObservableInt getSomeNumber() {
            return someNumber;
        }
        public void setSomeNumber(ObservableInt pSomeNumber) {
            someNumber.set(pSomeNumber.get());
        }
        public ObservableField<String> getSomeStr() {
            return someStr;
        }
        public void setSomeStr(ObservableField<String> pSomeStr) {
            someStr.set(pSomeStr.get());
        }
    }
    

    Custom setter and getter for the attribute

    @BindingAdapter("android:text")
    public static void bindIntegerInText(AppCompatEditText tv, int value) {
        tv.setText(String.valueOf(value));
    }
    @InverseBindingAdapter(attribute = "android:text")
    public static int getIntegerFromBinding(TextView view) {
        return Integer.parseInt(view.getText().toString());
    }
    

    Code in Activity

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMain2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
        mAge = new Age();
        mAge.setSomeNumber(new ObservableInt(3));
        mAge.setSomeStr(new ObservableField<>("Test"));
        binding.setAge(mAge);
        binding.btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mAge.setSomeNumber(new ObservableInt(4));
                mAge.setSomeStr(new ObservableField<>("Hello World"));
            }
        });
    }
    

    I make 4 demo with ObservableInt, Observable , normal String resource and binding String resource in the xml.

    <string name="helloworld">Hello World</string>
    

    activity_main3.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
    
        >
    
        <data>
    
            <variable
                name="age"
                type="example.com.testerapplication.Age"/>
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <android.support.v7.widget.AppCompatEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@={age.someNumber}"/>
    
            <android.support.v7.widget.AppCompatEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@={age.someStr}"/>
    
            <android.support.v7.widget.AppCompatEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/helloworld"/>
    
            <android.support.v7.widget.AppCompatEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{@string/helloworld}"/>
    
            <Button
                android:id="@+id/btn"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Test"
                />
        </LinearLayout>
    
    </layout>
    
    0 讨论(0)
  • 2020-12-15 07:04

    @CommonsWare is right, you should use ObservableField<Str‌​ing> instead of ObservableInt. If you really needit as number, just parse it Integer.valueOf(stringNumber).

    public ObservableField<Str‌​ing> someNumber;
    
    //and in xml code:
    
    <EditText
            android:layout_width="0dp"
            android:layout_height="@dimen/agro_item_height"
            android:layout_weight="1"
            android:inputType="numberDecimal"
            android:text="@={myObject.someNumber}"
            android:gravity="center_horizontal"/>
    

    EDITED: Or, as mentioned, write custom @InverseBindingAdapter

    public class MyEditTextBindingAdapters {
    
        @BindingConversion
        public static String intToStr(Integer value) {
            return value != null ? String.valueOf(value) : "";
        }
    
        @InverseBindingAdapter(attribute = "android:text")
        public static Integer captureIntValue(EditText view) {
            long value = 0;
            try {
                value = Integer.parseInt(view.getText().toString());
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            return value;
        }
    }
    
    0 讨论(0)
提交回复
热议问题