2

Problem: User should be able to login either by their Phone number or username (something they have set during registration). Both of these values would allow user to sign in. The Edittext field needs to be smart enough to determine what is being entered.So when the user enters a number as the first character, it should automatically add the country code phone number prefix and insert the typed character after the prefix.

This is my layout:

 <LinearLayout
        android:id="@+id/login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">


        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.design.widget.TextInputLayout
                android:id="@+id/emaillayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:background="@drawable/login_field"
                android:padding="2dp"
                android:paddingStart="5dp"
                android:visibility="visible">

                <AutoCompleteTextView
                    android:id="@+id/email"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@android:color/transparent"
                    android:hint="@string/prompt_email"
                    android:inputType="textEmailAddress"
                    android:maxLines="1"
                    android:padding="2dp"
                    android:singleLine="true" />

            </android.support.design.widget.TextInputLayout>

            <android.support.design.widget.TextInputLayout
                android:id="@+id/phlayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:background="@drawable/login_field"
                android:orientation="horizontal"
                android:padding="2dp"
                android:paddingStart="5dp"
                android:visibility="gone">


                <EditText
                android:id="@+id/et_ph"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@android:color/transparent"
                android:ems="10"
                android:hint="Phone number"
                android:inputType="phone" />

            </android.support.design.widget.TextInputLayout>

        </FrameLayout>



        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.design.widget.TextInputLayout

            android:id="@+id/pwdlayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"

            android:background="@drawable/login_field"
            android:orientation="horizontal"
            android:padding="2dp"
            android:paddingStart="5dp">

                <EditText
                android:id="@+id/password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@android:color/transparent"
                android:hint="@string/prompt_password"
                android:imeActionId="6"
                android:imeActionLabel="@string/action_sign_in_short"
                android:imeOptions="actionUnspecified"
                android:inputType="textPassword"
                android:maxLines="1"
                android:padding="2dp"
                android:singleLine="true" />
            </android.support.design.widget.TextInputLayout>

            <TextView
                android:id="@+id/pwdtoggle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end|center_vertical"
                android:text="SHOW"
                android:layout_marginRight="16dp"
                android:paddingTop="10dp"
                />
        </FrameLayout>

        <Button

            android:id="@+id/email_sign_in_button"
            style="?android:textAppearanceSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:layout_marginStart="5dp"
            android:layout_marginTop="16dp"
            android:background="@drawable/sausage_button"
            android:text="@string/action_sign_in"
            android:textStyle="bold" />


    </LinearLayout>

And this my code in the activity:

emailView.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) {

        }

        @Override
        public void afterTextChanged(Editable s)
        {

            if(isNumberOnly(s.toString()))
            {
                ChangeToPhoneNumber(s.toString());
            }

        }
    });

    numberView.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) {

        }

        @Override
        public void afterTextChanged(Editable s)
        {

            if(s.length()==0)
            {
               ChangeToUsername();
            }

        }
    });


}

private void ChangeToPhoneNumber(String s)
{

    emaillayout.setVisibility(View.GONE);
    phlayout.setVisibility(View.VISIBLE);
    numberView.setText("+61" + s);
    numberView.setSelection(mPhonenumberView.getText().length());
    mPhonenumberView.requestFocus();


}

private void ChangeToUsername()
{

        emaillayout.setVisibility(View.VISIBLE);
        phlayout.setVisibility(View.GONE);
        emailView.setText("");
        emailView.requestFocus();


}



public boolean isNumberOnly(String s)
{
    return s.matches("-?\\d+(.\\d+)?");
}

So by this implementation I am able to achieve what I wanted. Here are the screenshots:

Although I could achieve the results, I feel calling the text watcher all the time could be a bit of an overhead since I am using two separate views and added two instances of Textwatcher. In what ways can this be made more cleaner and efficient?. In addition I would like to understand how can I make sure the prefix is not erased but change the view to the username field when I press the backspace key on the keyboard?

android6p
  • 81
  • 12
  • 5
    what if my username is `99redballons`? I think your logic has to be a little bit stronger, and not just test for the first character entered. Maybe consider the numbers only + length of total numbers entered + format validator + a table of valid area codes. – TooManyEduardos Mar 09 '18 at 04:26
  • If both phone & username is allowed for signing in then it must be unique in your DataSource/DataBase. Referring to @TooManyEduardos's question, if you don't allow numeric literals at the beginning of username, then you already have figured out the correct way. Remove the second `TextInputLayout` and use a single one. And an alternative to `TextWatcher` would be just to remove it too. While you are using the text of the `View` in any method (such as sending to server or whatever) you can just check if the first entry is a number or a character and determine the type of input given. – Koushik Shom Choudhury Mar 09 '18 at 04:30

2 Answers2

0

You can one EditText to achieve the functionality as in

mPhoneAndEmailView.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) {

        }

        @Override
        public void afterTextChanged(Editable s)
        {
          if(isNumberOnly(s.toString()) && !mPhoneAndEmailView.contains("+61")){
             mPhoneAndEmailView.setText("+61" + s);
          }//utlimately when you clear number and start typing text it will ignore if and takes alpha or if it has only numbers first time it will append +61

        }
    });
Rajan Kali
  • 12,627
  • 3
  • 25
  • 37
0

Try it with this way its work for me. I use only one EditText and change all property Programmatically

MainActivity.java

public class MainActivity extends AppCompatActivity {
TextInputLayout textInputLayout;
AppCompatEditText edtPhnUsername;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    textInputLayout = findViewById(R.id.textInputLayout);
    edtPhnUsername = findViewById(R.id.edtPhnUsername);


    edtPhnUsername.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) {
            new Thread(new Runnable() {
                @Override
                public void run() {

                    changeEditTextState();
                }
            }).start();


        }

        @Override
        public void afterTextChanged(Editable s) {


        }
    });


}


private void changeEditTextState() {
    String uname = edtPhnUsername.getText().toString().trim();

    if (!TextUtils.isEmpty(uname)) {
        String desiredString = "";

        if (uname.length() >= 3) {
            desiredString = uname.substring(0, 3);
        }

        if (uname.contains("+61") && desiredString.equalsIgnoreCase("+61")) {
            changeToPhoneNumber();
        } else {
            changeToUsername();
        }
    } else {
        //default
        changeToUsername();
    }

}

private void changeToPhoneNumber() {
    textInputLayout.setHint("Phone number");
    edtPhnUsername.setInputType(InputType.TYPE_CLASS_PHONE);

    setEditTextMaxLength(10);



}

private void changeToUsername() {
    textInputLayout.setHint("Username");
    edtPhnUsername.setInputType(InputType.TYPE_CLASS_TEXT);
    setEditTextMaxLength(50);
}

public void setEditTextMaxLength(int length) {
    InputFilter[] filterArray = new InputFilter[1];
    filterArray[0] = new InputFilter.LengthFilter(length);
    edtPhnUsername.setFilters(filterArray);
}



}

activity_main.xml

 <android.support.design.widget.TextInputLayout
    android:id="@+id/textInputLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:orientation="horizontal"
    android:paddingStart="5dp"
    android:hint="Username"
    android:paddingLeft="5dp">


    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/edtPhnUsername"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text"
        android:maxLines="1"
        android:layout_weight="1" />

</android.support.design.widget.TextInputLayout>
Adil
  • 812
  • 1
  • 9
  • 29