Show button when all EditTexts are filled out by user - android

I have this login activity, when the user clicks on either Login or Register Button, different EditTexts appear. My question is how can i check if all EditTexts are filled out so the continueButton will be enabled?
(When Login is clicked, email and password must be filled, and when register is clicked, email, password and username must be filled)
ACTIVITY_LOGIN.XML
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/tableLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/yellow"
android:orientation="vertical"
tools:context=".LoginActivity">
<TableRow
android:id="#+id/welcomeTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8pt">
<TextView
android:id="#+id/welcomeTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/welcome_to"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="normal|bold" />
</TableRow>
<TableRow
android:id="#+id/logoTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/welcomeLogoImageView"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_span="2"
android:contentDescription="#string/todo"
android:scaleType="fitCenter"
app:srcCompat="#drawable/logo_medium" />
</TableRow>
<TableRow
android:id="#+id/loginInfoTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="12pt">
<TextView
android:id="#+id/infoEditText"
android:layout_width="wrap_content"
android:layout_height="70dp"
android:padding="6pt"
android:text="#string/ask_to_register_or_login"
android:textAlignment="center"
android:textColor="#android:color/black"
android:textSize="18sp" />
</TableRow>
<TableRow
android:id="#+id/loginOrRegisterTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="4pt"
android:layout_marginEnd="40dp"
android:layout_marginStart="40dp"
android:layout_marginTop="12dp">
<Button
style="#style/Widget.AppCompat.Button.Borderless"
android:id="#+id/chooseToLoginButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:background="#drawable/login_screen_button_unclicked"
android:onClick="chosenEvent"
android:text="#string/login" />
<Button
style="#style/Widget.AppCompat.Button.Borderless"
android:id="#+id/chooseToRegisterButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:background="#drawable/login_screen_button_unclicked"
android:onClick="chosenEvent"
android:text="#string/register" />
</TableRow>
<TableRow
android:id="#+id/nameTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:background="#android:color/white"
android:padding="4pt"
android:visibility="visible"
android:weightSum="1">
<TextView
android:id="#+id/nameTextView"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="0.3"
android:paddingEnd="2pt"
android:paddingStart="2pt"
android:text="#string/name"
android:textAlignment="textEnd"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="bold" />
<EditText
android:id="#+id/nameEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.65"
android:ems="10"
android:hint="#string/name"
android:inputType="textPersonName" />
</TableRow>
<TableRow
android:id="#+id/emailTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:background="#android:color/white"
android:padding="4pt"
android:visibility="visible"
android:weightSum="1">
<TextView
android:id="#+id/emailTextView"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="0.3"
android:paddingEnd="2pt"
android:paddingStart="2pt"
android:text="#string/email"
android:textAlignment="textEnd"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="bold" />
<EditText
android:id="#+id/emailEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.65"
android:ems="10"
android:hint="#string/email"
android:inputType="textEmailAddress" />
</TableRow>
<TableRow
android:id="#+id/passwordTableRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:background="#color/white"
android:padding="4pt"
android:visibility="visible"
android:weightSum="1">
<TextView
android:id="#+id/passwordTextView"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="0.3"
android:paddingEnd="2pt"
android:paddingStart="2pt"
android:text="#string/password"
android:textAlignment="textEnd"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="bold" />
<EditText
android:id="#+id/passwordEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.65"
android:ems="10"
android:hint="#string/password"
android:inputType="textPassword" />
</TableRow>
<TableRow
android:id="#+id/continueButtonTableRow"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="8pt"
android:visibility="visible">
<Button
android:id="#+id/continueButton"
style="#style/Widget.AppCompat.Button.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="80dp"
android:layout_marginStart="80dp"
android:background="#drawable/login_screen_button_unclicked"
android:enabled="false"
android:text="#string/continue_button"
android:visibility="visible" />
</TableRow>
</TableLayout>
LOGIN ACTIVITY:
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_login.*
LoginActivity:
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
}
private fun unclickAllChooseButtons() {
chooseToLoginButton.setBackgroundResource(R.drawable.login_screen_button_unclicked)
chooseToRegisterButton.setBackgroundResource(R.drawable.login_screen_button_unclicked)
}
private fun showEmailRow() {
emailTableRow.visibility = View.VISIBLE
}
private fun showNameRow() {
nameTableRow.visibility = View.VISIBLE
}
private fun showPasswordRow() {
passwordTableRow.visibility = View.VISIBLE
}
private fun hideAllRows() {
emailTableRow.visibility = View.GONE
passwordTableRow.visibility = View.GONE
nameTableRow.visibility = View.GONE
}
fun chosenEvent(view: View) {
when (view.id) {
R.id.chooseToLoginButton -> {
unclickAllChooseButtons()
chooseToLoginButton.setBackgroundResource(R.drawable.login_screen_button_clicked)
hideAllRows()
showEmailRow()
showPasswordRow()
}
R.id.chooseToRegisterButton -> {
unclickAllChooseButtons()
chooseToRegisterButton.setBackgroundResource(R.drawable.login_screen_button_clicked)
hideAllRows()
showNameRow()
showEmailRow()
showPasswordRow()
}
else -> {
unclickAllChooseButtons()
}
}
}
}

This is a hard one because what you need to do is to enable the button in real-time. So you have to listen each EditText and once a condition is met on the written text then you should set the button as enabled. There is another complexity here, which it is: what happened if the user goes back and then try to delete some text. There are 2 ways to solve this last issue, the first is to save a state of each EditText and the second is to also validate the data to be sent.
//You have to set initial state as false representing conditione haven'met
//Otherwise when you try to get the tag is gonna be null
boolean initialValidity = false;
emailEt.setTag(initialValidity);
passEt.setTag(initialValidity);
emailEt.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
String email = emailEt.getText().toString();
//You can improve this condition
if (email.trim().length() > 0 && email.contains("#") && email.contains(".")) {
emailEt.setTag(true);
if ((boolean) passEt.getTag()) {
sendButton.setEnabled(true);
}
} else {
emailEt.setTag(false);
sendButton.setEnabled(false);
}
}
});
passEt.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
String password = passEt.getText().toString();
//You can improve this condition
if (!password.contains(" ") && password.length() > 6) {
passEt.setTag(true);
if ((boolean) emailEt.getTag()) {
sendButton.setEnabled(true);
}
} else {
passEt.setTag(false);
sendButton.setEnabled(false);
}
}
});
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String email = emailEt.getText().toString();
String password = passEt.getText().toString();
//TODO add validation to send the data
//TODO send the data
}
});
What we are doing here is listening to both EditText and while the user is writting we check if the conditions are met. Both EditText while checking their own condition and also the other condition. This crossed checking allow us to enable or disable the Button if any EditText breaks the clauses in the conditions. Each EditText can know if the other has met the needed conditions by checking the tag which is a boolean representing if the conditions are met or not. I'm using enabled as an example, you could hide using setVisibility()

This is all the help you can get, cause you didn't include any code of yours. Also, my code is in Java, you should get the idea.
if(!edittext1.equals("") && !edittext2.equals("")){
// enable button
}

You must have different methods to validate that your forms are full, and finish with these validations:
public boolean validatePassword(String password){if(!password.equals("")){
if(password.length() == 6){ //Valid if the password is of certain sizes
this.password = password;
return true;
}
else {
Toast.makeText(this, "Length invalid", Toast.LENGTH_SHORT).show();
return false;
}
}
else {
Toast.makeText(this, "Please enter your password", Toast.LENGTH_SHORT).show();
return false;
}
}}
Method for each form.
You get the form data in the following way:
String pass = youreditText.getText().toString();
finally:
if(validatePassword(password)){ if(validateOtherForm(text){
//What you want to do
}}

Related

Edittext Move Next to Item of Recyclerview

I created a recycler view in which one is text view and other is edit text where data is added at runtime so I want to do that when I click of a keyboard next button then it moves to next edit text item issue is when I do it move to text view instead of edit text and so on... as shown in below image. what can I do that this is going through as my requirement? I tried all answers of s.o.f but failed.
here is my adapter code where the item is shown.
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
StudentMarks subject = subjectList.get(position);
holder.subjectName.setText(subject.getStudentsName());
holder.subjectId.setText(Collections.singletonList(subject.getStudentsId()).toString());
holder.subjectMarks.setText(subject.getStudentMarks());
if (!idStudent.contains(subject.getStudentsId())) {
idStudent.add(subject.getStudentsId());}
holder.subjectMarks.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
subjectList.get(position).setStudentMarks(holder.subjectMarks.getText().toString());
try {
String st_id = subjectList.get(position).getStudentsId();
for (int i = 0; i < id.size(); i++) {
if (id.get(i).equals(st_id)) {
id.remove(subjectList.get(position).getStudentsId());
value.remove(i);
}}
id.add(subjectList.get(position).getStudentsId());
value.add(holder.subjectMarks.getText().toString().trim());
} catch (Exception e) {
e.printStackTrace();
}
if (idStudent.toArray().length != id.toArray().length) {
listListener.onArrayListListener(id, value, position, "Please Enter Student Marks First");
} else {
listListener.onArrayListListener(id, value, position, "Student Marks Submitted");
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
holder.setIsRecyclable(false);
}
here is xml code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/add_student_category"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="#dimen/_180sdp"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_8sdp"
android:layout_marginBottom="#dimen/_8sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/add_marks_category"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/add_student_List"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:hint="#string/student_name"
android:inputType="none"
android:textColor="#color/greenish_shade"
android:textSize="#dimen/_12sdp"
tools:ignore="Deprecated,LabelFor" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/add_marks_category"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="#dimen/_80sdp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/add_student_category"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/add_student_category"
app:layout_constraintTop_toTopOf="#id/add_student_category">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/add_exam_marks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/obtain_marks"
android:inputType="number"
android:imeOptions="actionNext"
android:focusable="true"
android:focusableInTouchMode="true"
android:textAlignment="center"
android:textColor="#color/greenish_shade"
android:textColorHint="#color/greenish_shade"
android:textSize="#dimen/_12sdp"
tools:ignore="LabelFor" />
</com.google.android.material.textfield.TextInputLayout>
<View
android:id="#+id/view"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:layout_marginStart="#dimen/_8sdp"
android:layout_marginEnd="#dimen/_8sdp"
android:background="#color/light_black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/add_student_category" />
<TextView
android:id="#+id/student_idss"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
use android:inputType="text" in editText in xml file
if you are adding dynamic edittexts then you can do it like this
editText.setInputType(InputType.TYPE_CLASS_TEXT);
refere this site where you can found various input types according to your need like for password(this will hide the typed text), numbers(numbered keyboard),etc
you can add android:maxLines="1" & android:inputType="text" to your EditText. It will surely work.

Form Validation in android TextInputLayout not working correctly

I am trying to validate the form, i am using TextInputLayout error to show the error, when i click submit button in empty form, the error is shown in only Name field, and the error is not hiding when i fill the name text. Also the other fields not showing validation error.
activity_form.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:id="#+id/nameTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="#+id/formNameEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/form_hint_name"
android:inputType="textPersonName"
android:imeOptions="actionNext"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/EmailTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="#+id/formEmailEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/form_hint_email"
android:inputType="textEmailAddress"
android:imeOptions="actionNext"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/PhoneTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/form_hint_mobile_number"
android:imeOptions="actionNext"
android:id="#+id/formMobileEdit"
android:inputType="number"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/AlternateTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/form_hint_alternate_number"
android:imeOptions="actionNext"
android:id="#+id/formAlternateEdit"
android:inputType="number"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/JEETextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:id="#+id/formJeeEdit"
android:hint="#string/form_hint_jee"
android:inputType="number"
android:minLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/PercentageTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/form_hint_percentage"
android:imeOptions="actionNext"
android:id="#+id/formPerEdit"
android:inputType="numberDecimal"
android:minLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/CityTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:hint="#string/form_hint_city"
android:id="#+id/formCityEdit"
android:inputType="text" />
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Spinner
android:id="#+id/deptSpinner"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
>
</Spinner>
<Spinner
android:id="#+id/SourceSpinner"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
</Spinner>
</LinearLayout>
<Button
android:id="#+id/submit_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/roundedbutton"
android:text="#string/form_submit_btn" />
</LinearLayout>
</ScrollView>
FormActivity.java
mSubmitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Validation();
}
});
private void Validation(){
boolean isValid = true;
String dept = mDepartmentSpinner.getSelectedItem().toString();
String source = mSourceSpinner.getSelectedItem().toString();
String name = NameInputLayout.getEditText().getText().toString();
if(NameInputLayout.getEditText().getText().toString().isEmpty()){
NameInputLayout.setError("Enter Name");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
Log.d("form error", "Error removed");
}
String email = EmailInputLayout.getEditText().getText().toString();
if(EmailInputLayout.getEditText().getText().toString().isEmpty()){
NameInputLayout.setError("Enter Email");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
String phone = PhoneInputLayout.getEditText().getText().toString().trim();
if(phone.isEmpty()){
NameInputLayout.setError("Enter Phone Number");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
String alternate_num = AlternateInputLayout.getEditText().getText().toString();
if(alternate_num.isEmpty()){
NameInputLayout.setError("Enter Alternate Number");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
String jee_marks = JeeInputLayout.getEditText().getText().toString();
if(jee_marks.isEmpty()){
NameInputLayout.setError("Enter Roll Number");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
String percentage = PercentageInputLayout.getEditText().getText().toString();
if(percentage.isEmpty()){
NameInputLayout.setError("Enter Percentage");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
String city = CityInputLayout.getEditText().getText().toString();
if(city.isEmpty()){
NameInputLayout.setError("Enter Name");
isValid = false;
}else {
NameInputLayout.setErrorEnabled(false);
}
if(isValid){
Boolean insert = dbHelper.insertForm(name,email,phone,alternate_num,jee_marks,percentage,city,dept,source);
if(insert == true){
Toast.makeText(getApplicationContext(),"Form Submitted",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(FormActivity.this, MainActivity.class);
startActivity(intent);
}else {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_SHORT).show();
}
}
}
here is code snippet to remove error(user text change listener in edittext) you need to call for every edit text and textinput layout.
public static void addTextChangedListener(EditText e, final TextInputLayout t) {
e.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() > 0) {
if (!TextUtils.isEmpty(t.getError())) {
t.setError(null);
t.setErrorEnabled(false);
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
and second thing you are validation EmailInputLayout and setting erroer to NameInputLayout in each input field.
-do copy paste but smartly.
It seems you are using the same textInputlayout (NameInputLayout) with all your fields.
Hence after entering the name , when the else block is executed the errorEnabled is set to false , causing other error to not set.
And for removing error in your else case do the following:-
NameInputLayout.setError(null)
instead of :-
NameInputLayout.setErrorEnabled(false);
Otherwise you will have to set setErrorEnabled to true, again to use it.

How to request or remove the focus on edittext using data binding

I am learning mvvm structure and making an app using mvvm structure and data binding also.
Now, what I want to do is, I wanted to fetch a user from sharedpreference, If I am getting a user successfully then, I would set the name of usr to edittext1. In that case, I want to request focus on edittext2.
How to achieve that using databinding? (in such a way that i don't
have to use activity. The job should be done using view model and xml
only.)
I have tried that using following way.
StartGameViewModel
public class StartGameViewModel extends ViewModel {
public static String TAG="StartGameViewModel";
private Preference<User> preference;
public ObservableField<String> player1Name=new ObservableField<>("");
public ObservableField<String> player2Name=new ObservableField<>("");
public ObservableBoolean shouldRequestFocus=new ObservableBoolean(false);
StartGameViewModel(Preference preference){
this.preference=preference;
}
public void getPreference() {
preference.get(Constants.CURRENT_USER,User.class)
.subscribe(new Observer<User>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(User user) {
player1Name.set(user.name);
shouldRequestFocus.set(true);
}
#Override
public void onError(Throwable e) {
Log.i(TAG,"user is logged out");
}
#Override
public void onComplete() {
Log.i(TAG,"Completed Preference");
}
});
}
}
activity_start_game.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.StartGameActivity">
<data>
<variable
name="startGameViewModel"
type="com.sevenbits.android.mvvmsample.viewmodel.StartGameViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/splash_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter Players Name"
android:textSize="24sp"
android:textColor="#color/white"
app:layout_constraintVertical_bias="0.75"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/input_layout"
app:layout_constraintTop_toTopOf="parent"
/>
<LinearLayout
android:id="#+id/input_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:background="#color/white"
android:elevation="20dp"
android:orientation="vertical"
android:paddingBottom="40dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
tools:layout_editor_absoluteX="8dp">
<android.support.design.widget.TextInputLayout
android:id="#+id/til_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player1"
android:text="#{startGameViewModel.player1Name}"
app:addTextChangedListener="#{startGameViewModel.Player1Watcher}" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/til_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player2"
android:text="#{startGameViewModel.player2Name}"
app:addTextChangedListener="#{startGameViewModel.Player2Watcher}" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<Button
android:id="#+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bg_button"
android:elevation="20dp"
android:gravity="center"
android:paddingBottom="20dp"
android:paddingEnd="40dp"
android:paddingStart="40dp"
android:paddingTop="20dp"
android:text="Start"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/input_layout" />
</android.support.constraint.ConstraintLayout>
</layout>
StartGameActivity:
public class StartGameActivity extends AppCompatActivity {
ActivityStartGameBinding activityStartGameBinding;
StartGameViewModel startGameViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initDataBinding();
setStartGameListener();
}
private void initDataBinding() {
activityStartGameBinding = DataBindingUtil.setContentView(this, R.layout.activity_start_game);
StartGameViewModelFactory startGameViewModelFactory= Injection.provideStartGameViewModelFactory(this);
startGameViewModel = ViewModelProviders.of(this,startGameViewModelFactory).get(StartGameViewModel.class);
activityStartGameBinding.setStartGameViewModel(startGameViewModel);
startGameViewModel.getPreference();
if(startGameViewModel.shouldRequestFocus.get())
findViewById(R.id.et_player2).requestFocus();
}
private void setStartGameListener() {
findViewById(R.id.start_button).setOnClickListener(v -> {
Intent intent=new Intent(StartGameActivity.this,GameActivity.class);
intent.putExtra(Constants.PLAYER1_NAME,startGameViewModel.player1Name.get());
intent.putExtra(Constants.PLAYER2_NAME,startGameViewModel.player2Name.get());
startActivity(intent);
});
}
}
Very simple via binding adapter
#JvmStatic
#BindingAdapter("requestFocus")
fun requestFocus(view: TextView, requestFocus: Boolean) {
if (requestFocus) {
view.isFocusableInTouchMode = true
view.requestFocus()
}
}
<EditText
android:id="#+id/et_company"
android:layout_width="0dp"
android:layout_height="match_parent"
android:imeOptions="actionDone"
android:inputType="textCapSentences"
android:maxLength="32"
android:scrollbars="vertical"
app:requestFocus="#{company.requestFocus}" />
I know this is an old question, but I was not able to solve the issue with the current answer. Posting my answer here:
in XML:
<EditText
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/elevation15"
app:requestFocus="#{viewmodel.focus}"/>
And in the viewModel, I had a Boolean variable declared as
val focus = true
And the binding adapter is as follows:
companion object{
#BindingAdapter("requestFocus")
#JvmStatic fun requestFocus(editText: EditText, requestFocus: Boolean){
if(requestFocus){
editText.isFocusableInTouchMode = true
editText.requestFocus()
}
}
}
Basically what is happening here is, Since app:requestFocus is written inside the xml, it will invoke the binding adapter with the focus Boolean, which is given as the value for the attribute for app:requestFocus.
In my case, I didn't want to remove focus, that's why I used Boolean. If it needs to be changed, using a livedata and set the value, and update the binding adapter accordingly
Disclaimer: I am new to MVVM and Databinding, someone please correct me if I am wrong.

EditText value is reversed

I've got an odd one. I'm trying to format some text while the user types into an EditText field. I am using the TextWatcher and responding to afterTextChanged event (code below). What is odd is after the first time this logic runs the text starts to become reversed. It seems that the Editable object contains the string backwards. Does anyone have any idea how to fix this?
_textWatcher = new TextWatcher()
{
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3)
{
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3)
{
}
#Override
public void afterTextChanged(Editable editable)
{
Editable e = textView.getText();
String text = e.toString();
logger.d("[FormListAdapter][addTextChangedListener] Format Text: " + text);
Number numVal = FormFieldBusiness.ConvertStringToNumber(text, formField.GetFormFieldType());
String fText = FormFieldBusiness.GetFormattedValue(numVal, formField.GetFormFieldType());
editText.removeTextChangedListener(_textWatcher);
textView.setText(text);
editText.addTextChangedListener(_textWatcher);
}
};
editText.addTextChangedListener(_textWatcher);
* UPDATE *
In an attempt to help anyone out there who's looking at this here is my XML layout file.
As I mentioned before the text is correct until after the first the time setText method is called. After that the Editable object is reversed.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="120dp">
<!-- Top Layout -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:weightSum="10"
android:id="#+id/TopLayout">
<TextView
android:id="#+id/TitleTextView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="7"
android:gravity="center_vertical"
android:text="Headling Rent (pa)"
android:textSize="16dp"
style="#style/KelFormListItemLabel" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:weightSum="2"
android:background="#color/formListItemValueBackgroundColor">
<ImageView
android:id="#+id/CurrencyIconView"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="0"
android:src="#drawable/icon_currency_pound"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp" />
<EditText
android:id="#+id/ValueTextView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="right|center_vertical"
android:text="20,000"
android:textSize="16dp"
android:inputType="number"
android:selectAllOnFocus="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:textIsSelectable="true"
style="#style/KelFormListItemValue"/>
</LinearLayout>
</LinearLayout>
<!-- Bottom Layout -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:weightSum="10"
android:id="#+id/BottomLayout"
android:layout_below="#+id/TopLayout">
<TextView
android:id="#+id/BottomTitleTextView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="7"
android:gravity="center_vertical"
android:text="Headling Rent (pa)"
android:textSize="16dp"
style="#style/KelFormListItemLabel" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:weightSum="2"
android:background="#color/formListItemValueBackgroundColor">
<ImageView
android:id="#+id/BottomCurrencyIconView"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="0"
android:src="#drawable/icon_currency_pound"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp" />
<EditText
android:id="#+id/BottomValueTextView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="right|center_vertical"
android:text="20,000"
android:textSize="16dp"
android:inputType="number"
android:selectAllOnFocus="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:textIsSelectable="true"
style="#style/KelFormListItemValue"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
The issue is you are setting the text in the EditText field (even though you have removed the listener) you are listening for. this is causing the cursor to move to the beginning of the line, therefore making it type backwards
try changing from a TextWatcher to TextView.OnEditorActionListener and listen for the action key set on the EditText so when they hit the action key, it does your desired functionality.
add
android:imeOptions="actionDone"
to your button xml and assign it with
TextView.OnEditorActionListener editingActionListener = new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN) || actionId == EditorInfo.IME_ACTION_DONE) {
//do stuff where you set the text here
}
return true;
}
};
editText.setOnEditorActionListener(editingActionListener);
alternatively, you can use OnFocusChangeListener
View.OnFocusChangeListener focusChangeListener = new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (v.getClass().equals(EditText.class)) {
if (!hasFocus) {
//do your stuff here
}
}
}
};
editText.setOnFocusChangeListener(focusChangeListener);
Simply move the cursor to the correct position in your TextWatcher after setting the EditText content:
#Override
public void afterTextChanged(Editable editable)
{
...
int position = editText.getSelectionStart();
editText.setText(text);
editText.setSelection(position);
...
}

Temporary disable EditText

I want EditText to temporarily not gain foucs.
Scenario is : I have two EditTexts. Whenever any EditText's text is changed, I want another EditText to not to respond to user clicks until another predefined event occurs.
To achieve that I tried this :
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
registerBroadcastReceivers();
}
// Register BroadcastReceivers
private void registerBroadcastReceivers() {
Log.d(TAG, "Registering broadcast receivers.");
// Google response receiver
googleResponseReceiver = new GoogleAPIResponseReceiver();
IntentFilter googleResponseIntentFilter = new IntentFilter(
RS_GoogleApiIntentService.ACTION_RECEIVED_GOOGLE_RESPONSE);
googleResponseIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(
googleResponseReceiver, googleResponseIntentFilter);
}
editText1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// Set EditText non-focusable
MyActivity.this.editText2.setFocusableInTouchMode(false);
}
});
.
.
.
// Somewhere in one function I call below function to start an IntentService.
.
.
.
// Call Google API with given URL
private void CallGoogleApiWithUrl(String url, int requestId) {
Intent intent = new Intent(this, RS_GoogleApiIntentService.class);
intent.putExtra(RS_GoogleApiIntentService.EXTRA_URL_STRING, url);
intent.putExtra(RS_GoogleApiIntentService.EXTRA_GOOGLE_API_REQUEST_ID,
requestId);
startService(intent);
}
// Broadcast receiver for Google API response
public class GoogleAPIResponseReceiver extends BroadcastReceiver {
// Enabling EditText works up to this point.
#Override
public void onReceive(Context context, Intent intent) {
// Stops working now onwards.
}
}
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Set EditText focusable
MyActivity.this.editText2.setFocusableInTouchMode(true);
}
Layout :
<LinearLayout
style="#style/create_trip_activity_components_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal" >
<EditText
android:id="#+id/from_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:ems="10"
android:hint="#string/from_location_hint"
android:imeOptions="actionDone"
android:imeActionLabel="Done"
android:inputType="text" >
<requestFocus />
</EditText>
<Button
android:id="#+id/use_current_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:onClick="useCurrentLocation"
android:text="#string/use_current"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:contentDescription="#string/swap_button_description"
android:onClick="swapLocations"
android:scaleType="fitStart"
android:src="#drawable/swap" />
<EditText
android:id="#+id/to_location"
style="#style/create_trip_activity_components_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:gravity="left"
android:hint="#string/to_location_hint"
android:imeOptions="actionDone"
android:imeActionLabel="Done"
android:inputType="text" >
</EditText>
<LinearLayout
style="#style/create_trip_activity_components_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center_vertical"
android:orientation="horizontal" >
<EditText
android:id="#+id/departuretime_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:ems="10"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:hint="#string/departure_date_hint"
android:inputType="datetime" >
</EditText>
<EditText
android:id="#+id/departuretime_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:ems="10"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:hint="#string/departure_time_hint"
android:inputType="datetime" >
</EditText>
</LinearLayout>
<Button
android:id="#+id/pick_match_create_trip"
style="#style/big_centered_button_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:onClick="pickMatchesButtonClicked"
android:text="#string/pick_your_matches" />
<TextView
style="#style/create_trip_activity_components_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="75dp"
android:text="#string/current_location_textlabel"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="#+id/current_location_text"
style="#style/create_trip_activity_components_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginTop="5dp"
android:text=""
android:textAppearance="?android:attr/textAppearanceSmall" />
<ListView
android:id="#+id/places_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:cacheColorHint="#00FFFF"
android:background="#color/white" >
</ListView>
EditText never gains focus again. Disabling focus works but enabling it again does not. I also tried using editText2.setEnabled(); method. It did not work, too.
Its really Simple my friend.
You can try something like below:
editText1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// Set EditText non-focusable
editText2.setEnable(false);
editText2.setClickable(false);
}
});
.
. // some work
.
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Set EditText focusable
editText2.setEnable(true);
editText2.setClickable(true);
}
Just update your code something like above and try. that will surly works. if not then let me know, i will help you.
Enjoy Coding... :)
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
editText2.setEnable(false);
editText2.setClickable(false);
}
}, 20);
try this..
editText2.clearFocus();
You set editText2.requestFocus(); when ever you want to focus on EditText.
write it in manifest file of activity, It defocus the edittext by creation activity at first time. and re gain the focus by touching on Edit text
android:windowSoftInputMode="adjustPan|stateHidden"
you may use the following code and manipulate accordingly by java.
`<EditText ...
android:clickable="false"
android:cursorVisible="false"
android:focusable="false"
android:focusableInTouchMode="false">
</EditText>'

Categories

Resources