EditText LiveData Two-way binding - android

Okay, so I have a ViewModel with a getter getTitle() that returns MutableLiveData<String>.
<EditText
style="#style/Widget.EditText.FullWidth"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/label_title"
android:inputType="text"
android:text="#={ viewModel.title }" />
This works fine at first: the EditText contains the value of the MutableLiveData when it first appears. However, if the value of this data is updated using MutableLiveData.setValue() (such as by another EditText, or from my code), then the value inside of the text box does not change. How do I fix this?

This works properly in the new version of Android Studio, which supports binding to LiveData objects properly.

Related

How can I get '#id/view_name' dynamically for databinding?

I have a TextView that I want to change the position by other view.
For example,
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv"
...
app:layout_constraintBottom_toTopOf="#id/btn_to_follow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
I have a button btn_to_follow, btn_to_follow2, btn_to_follow3.
So, I'd like to change app:layout_constraintBottom_toTopOf attribute dynamically with those three values.
I have a data class for state.
data class ButtonState(type: String){
val followPosition = R.id.btn_to_follow
}
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv"
...
app:layout_constraintBottom_toTopOf="#{vm.followPosition}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
I tried to change followPosition with 'R.id.xxx' values which are int values. It didn't work.
So, How can I approach what I expect??
I think what you are missing is "Live" portion of it.
app:layout_constraintBottom_toTopOf="#{vm.followPosition}"
It works, it does get the value from the followPosition in the ViewModel where followPosition is an Int.
But there isn't any implicit way how it gets updated. View was inflated and it no longer cares what is in followPosition.
You need followPosition to be LiveData<Int> or the parent data class to be stored in LiveData.

How to refrence another view sibling as adapter argument in data binding

I have 2 edit texts in my view and I'm using data binding. What I want to achieve is whenever the first text view had 5 characters, the focus passes on to the next edit text, and whenever that edit text also had 5 characters, the focus should be removed from the whole view.
This is the code I wrote for my binding adapter:
#BindingAdapter("setMaxLength", "nextPart")
fun EditText.onTextChange(maxLength: Int, nextPart: EditText) {
filters = arrayOf<InputFilter>(InputFilter.LengthFilter(maxLength))
addOnTextChangeListener {
if (it.length == maxLength) {
clearFocus()
nextPart.requestFocus()
}
}
}
I don't know how I should pass these 2 arguments to my function in xml.
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/firstPart"
nextPart="alphabet"
setMaxLength="#{5}" />
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/alphabet"
setMaxLength="#{5}" />
This code has build issues with error:
Cannot find a setter for <androidx.appcompat.widget.AppCompatEditText setMaxLength> that accepts parameter type 'int'
If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.
I'm not sure how I could do this, also addOnTextChangeListener is a text watcher and the functionality is tested.
Am I even on the right path here? Any ideas would be appreciated.
Try doing it like this
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/firstPart"
nextPart="#{alphabet}"
setMaxLength="#{5}" />

How to assign an textedit value to a float variable in Android Studio Kotlin

very newbie in Android Studio Kotlin and am struggling to pass a value from an edittext object to a float variable, but it is proving to be a challenge. I was able to do it but only after making use of 2 additional variables; however I can't believe it can't be done directly.
This is how I managed to do it:
var temp: EditText = findViewById(R.id.txtPriceA)
var temp2: String = temp.getText().toString()
var priceA: Float = temp2.toFloat()
The XML for the edittext is this:
<EditText
android:id="#+id/txtPriceA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:autofillHints=""
android:gravity="center"
android:hint="#string/enter_price_a"
android:inputType="numberDecimal"
android:textColor="#0E0B0B"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="#+id/textView5"
app:layout_constraintHorizontal_bias="0.526"
app:layout_constraintStart_toStartOf="#+id/textView5"
app:layout_constraintTop_toBottomOf="#+id/textView5"
tools:text="$23.45" />
I thank you all in advance for any help.
Ray.
You can skip the intermediate variable like so:
val priceA = findViewById(R.id.txtPriceA).getText().toString().toFloat()
If you are just getting started, and only getting the hang of the framework you should consider this as the only way.
After you got the hang of things I think you should take a look at viewmodels and databinding, that way you will be able to write an inverse binding adapter that would map the value of the text field to a variable in your viewmodel as a float directly.
As you get more comfortable with kotlin, you could also write an extension property for this purpose. Combined with kotlin synthetic view binding your code could look like this:
val priceA = txtPriceA.floatValue
Good luck with your android endeavors!

MutableLiveData doesn't work, ObservableField does - why?

I have a very simple code in XML:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:text="#={viewModel.password}"
android:enabled="#{viewModel.inputEnabled}">
Now when viewModel.inputEnabled is a MutableLiveData<Boolean> underneath, it simply doesn't work, edit is always enabled, regardless of value of inputEnabled. However, it takes only to change inputEnabled to an ObservableField<Boolean> (and switch setValue to set) such that it immediately starts working.
Why is that so? How can I make MutableLiveData work correctly?
Note, that this field is used in three places (to enable/disable form during processing).
I ran in to same issue....make sure to call following in your activity/fragment:
binding.setLifecycleOwner(this)

Enable/disable EditText based on whether adapter has items

I'm using Data Binding Library. I have this in the XML:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="#{!myAdapter.isEmpty}"/>
I want that EditText to be enabled only when Spinner adapter is not empty. When app starts, EditText is disabled. So far, so good.
Then, in my activity, items are inserted in the adapter. But after:
myAdapter.notifyDataSetChanged();
EditText is not enabled. Do I have to do anything more?
To have an ability to notify data binding about something you could use ObservableBoolean like this:
...
<variable name="isAdapterEmpty"
type="android.databinding.ObservableBoolean" />
...
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="#{!isAdapterEmpty}"/>
And then notify databinding about changes like this:
myAdapter.notifyDataSetChanged();
isAdapterEmpty.set(myAdapter.isEmpty());
Or you can make your own method inside your adapter that will return ObservableBoolean instead of simple boolean and provide ability to manage this value to adapter.

Categories

Resources