DataBinding background drawable update based on focus - android

I have a TextInputEditText inside a TextInputLayout.
I want to change the TextInputLayout's background based on whether the EditText has focus or not.
I can easily accomplish that by observing the edittext's focus from the activity and then update the background accordingly.
But it seems such a waste to update the element from the activity if I'm already using Data Binding.
Is there a way to reference the TextInputLayout's background from the focus change callback inside the EditText?
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/input_field_unselected_background">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:inputType="text"
android:hint="#string/hint_placeholder"
android:background="#android:color/transparent"/>
</com.google.android.material.textfield.TextInputLayout>

Yes you can, just keep in mind that you have to account for when you lose focus. It could be due to the back button, switching input fields or hitting enter on the keyboard. Since you do not know what the user will do you can account for that as discussed here based on your use case..
In your layout
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#{viewModel.hasFocus ? #drawable/background_focused : #drawable/background_unfocused}">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:inputType="text"
android:hint="#string/hint_placeholder"
android:background="#android:color/transparent"
android:onClick="#{() -> viewModel.setFocus(true)}"/>
</com.google.android.material.textfield.TextInputLayout>
A lambda is used to call the appropriate background based on the viewmodel data while onClick determines if it is in focus.
In you viewmodel (Kotlin)
val hasFocus = MutableLiveData<Boolean>().apply{postValue(false)}
fun setFocus(value: Boolean){
hasFocus.value = value
}

Related

Keyboard showed when focus is on AutoCompleteTextView

I don't understand what I'm doing wrong. I would like to show only dropdown menu. The result is like the photo below: I can edit on it and keyboard is showed. What I'm missing?
Aspected (without pointer enabled):
Result:
XML layout
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/gender_container"
style="#style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
android:hint="Gender"
app:layout_constraintTop_toBottomOf="#+id/year_of_bird_container">
<AutoCompleteTextView
android:id="#+id/gender_spinner"
android:layout_width="match_parent"
android:inputType="none"
android:layout_height="match_parent"/>
</com.google.android.material.textfield.TextInputLayout>
From Fragment
private fun setAdapter() {
val genderList = mutableListOf(
Gender.MALE.toString(),
Gender.FEMALE.toString(),
Gender.OTHER.toString(),
Gender.PREFER_NOT_TO_SAY.toString()
)
val adapter = ArrayAdapter(
requireContext(), R.layout.simple_spinner_dropdown_item, genderList
)
binding.genderSpinner.setAdapter(adapter)
}
I used AutoCompleteTextView in my previous project and the usage was same. But to be sure i just created fresh project and added your code, it's working fine too.
Maybe adding android:imeOptions="actionDone" to the previous EditText might solve it, because it can be use the keyboard and when you finish with it, if it's not actionDone keyboard stays for next component.
Other than that, check about your other code parts that effect this, like onFocus or onClick events. If it is not about them i suggest you to create new project and try this again step by step to find what is causing this.
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/gender_container"
style="#style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
android:hint="Gender"
app:layout_constraintTop_toBottomOf="#+id/year_of_bird_container">
<AutoCompleteTextView
android:id="#+id/gender_spinner"
android:layout_width="match_parent"
android:inputType="none"
android:clickable="false"
android:cursorVisible="false"
android:focusable="false"
android:layout_height="match_parent"/>
</com.google.android.material.textfield.TextInputLayout>
You can try this if you don't want to show the Softkeyboad but retain the cursor/caret. Put this in your activity
window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
Screenshot showing the cursor/caret active with no SoftKeyboard
I suggest you to use spinner like below. AutoCompleteTextView not a spinner actually.
<androidx.appcompat.widget.AppCompatSpinner
android:id="#+id/spinner"
style="#style/AddressSpinnerTheme"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="5dp"
app:entries="#{viewModel.uiState.value.spinnerItemList}"
app:newValue="#{viewModel.uiState.value.spinnerSelectedItem}"
app:onItemSelected="#{listener}" />

Couldn't enable button using xml and data binding

I'm want to enable button when repeatPasswordInputEditText is not empty, I tried to enable it with android:enabled="#{!repeatPasswordInputEditText.text.toString().isEmpty()}" but it doesn't work, why ? I'm also calling binding.lifecycleOwner = this in onCreateView
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/uRepeatPassword"
android:layout_width="384dp"
android:layout_height="75dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:hint="#string/repeat_password_hint"
app:passwordToggleEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/uNewPassword">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/repeatPasswordInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:text="#{passwordChangeViewModel._repeatPassword}"
android:background="#color/white"
app:passwordToggleEnabled="false"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/changePasswordButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Change Password"
android:enabled="#{!repeatPasswordInputEditText.text.toString().isEmpty()}"
app:layout_constraintTop_toBottomOf="#+id/uRepeatPassword">
</com.google.android.material.button.MaterialButton>
You cannot listen to changes in EditText text inside the XML itself.
In your code, you have
android:text="#{passwordChangeViewModel._repeatPassword}"
Seems like you are trying to use two-way data-binding here where _repeatPassword is a MutableLiveData<String>. This won't work because it is just one-way right now. You need to replace # with #= to make it two way.
Now that you have two-way data binding working, you can use the value of this live data to enable/disable your button:
android:enabled="#{!_repeatPassword.empty}"
If you are not using two-way data binding, you will have to put the logic in your Activity/Fragment:
repeatPasswordInputEditText.doAfterTextChanged { text ->
changePasswordButton.enabled = text.isNotEmpty()
}

TextInputLayout hint not working when using databinding

I am using databinding together with the TextInputLayout/TextInputEditText combo as shown in the xml.
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/lastname_input_layout"
style="#style/TextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:endIconMode="clear_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/firstname_input_layout"
app:visible="#{viewModel.showFields}">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/lastname_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/lastname"
android:inputType="textCapWords"
android:text="#={viewModel.lastName}"
android:textAppearance="#style/TextAppearance.Input" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/email_input_layout"
style="#style/TextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:endIconMode="clear_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/lastname_input_layout"
app:visible="#{viewModel.showFields}">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/email_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#{viewModel.watchMediaTextHint}"
android:inputType="#{viewModel.watchMediaInputType}"
android:text="#={viewModel.mediaText}"
android:textAppearance="#style/TextAppearance.Input" />
</com.google.android.material.textfield.TextInputLayout>
As you can see, both fields are theoretically the same, the only difference is that one of them has the hint text given with a string resource, the other one with a databinding. Both have the same style, text appearance and so on, yet, the hint on the TextInputEditText using the databinding has different color. Also, when the view gets focus, the label doesn't animate up, as it does with the first field.
Setting the hint with a string resource gets this behavior to go back to normal, any ideas on why is this anomaly happening? I would prefer to solve this with a databinding rather than a programmatic solution.
Thanks.
The hint attribute only works in combination with databinding, if it is set to <TextInputLayout> instead of <TextInputEditText>.
The <TextInputEditText>s hint attribute is only applied once during inflation and thereby will not be updated/applied when used in combination with databinding.
Heads up for #Mike M.'s comment. I converted it as an answer, in order to be found more easily by others.

TextInputLayout not animating when used as an item of RecyclerView [duplicate]

This question already has an answer here:
TextInputLayout has no effect for giving hint programmatically in EditText
(1 answer)
Closed 5 years ago.
I am getting a list of strings from server and should be shown as Hints of TextInputLayout. Everything is working fine, I am getting list of strings from server and based upon the list size I am able to show that many number of views and string values as hint.
The problem I am facing is when they are getting focus, the hint doesn't animate as expected. They looks like a normal EditText.
Below is my code:
layout_input.xml
<android.support.design.widget.TextInputLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="#+id/inputAttr"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
MyViewHolder.kt
internal class InputAttributeHolder(item: View) : RecyclerView.ViewHolder(item) {
private val attrName: TextInputEditText = item.inputAttr
fun bind(attr: Attribute) {
attrName.hint = attr.name
}
}
NOTE: The hint is set dynamically in ViewHolder while binding, not statically in XML. When I am setting it in XML, it's working fine. But dynamically setting hint doesn't animate.
use EditText inside android.support.design.widget.TextInputLayout
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:hint="#string/hint_email"
android:inputType="textEmailAddress"
android:textColor="#android:color/white"
android:textColorHint="#android:color/white" />
</android.support.design.widget.TextInputLayout>

Double exclamation mark on EditText setError when used on a password type field

In my application I use the Design Support Library's TextInputLayout around all my EditTexts that require the hint to label effect. However I noticed an adverse effect of doing so - applying it to a password field will make the setError method apply two exclamation marks: one in the middle of the EditText and one at the proper place, slightly covering the "eye" (password visibility) icon.
This only happens on fields that have the inputType set to textPassword.
How could I fix this?
EDIT:
XML layout
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/loginEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/hint_email"
android:inputType="textEmailAddress"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/hint_password"
android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
try to set your error message just for TextInputLayout and remove it from editText object.

Categories

Resources