rapid3642 rapid3642 - 2 months ago 64
Android Question

TextEdit validation overlays show password icon

I have a password TextEdit field that im currently doing validation on and it displays an icon at the end of the TextEdit field to toggle the actual text. When someone enterted in a incorrect password or the passwords dont match it displays an error icon indicating that there was an error with the text entered and this error icon goes right underneath the "show text" icon for the TextEdit field. How do I move either the error icon from validation, or how do I move the "show text" icon?

app displaying both error icon and show text icon

RegisterActivity

public class RegisterActivity extends AppCompatActivity {
private static final String TAG = "RegisterActivity";

@InjectView(R.id.input_name) EditText _nameText;
@InjectView(R.id.input_email) EditText _emailText;
@InjectView(R.id.input_password) EditText _passwordText;
@InjectView(R.id.input_confirmPassword) EditText _confirmPasswordText;
@InjectView(R.id.btn_signup) Button _signupButton;
@InjectView(R.id.link_login) TextView _loginLink;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
ButterKnife.inject(this);

_signupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signup();
}
});

_loginLink.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Finish the registration screen and return to the Login activity
finish();
}
});
}

public void signup() {
Log.d(TAG, "Begin Signup process...");

if (!validate()) {
onSignupFailed();
return;
}

_signupButton.setEnabled(false);

final ProgressDialog signupProgressDialog = new ProgressDialog(RegisterActivity.this,
R.style.Theme_IAPTheme);
signupProgressDialog.setIndeterminate(true);
signupProgressDialog.setMessage("Creating Account...");
signupProgressDialog.show();

String name = _nameText.getText().toString();
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
String confirmPassword = _confirmPasswordText.getText().toString();

// TODO: Implement your own signup logic here.

Response.Listener<String> responseListener = new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
Log.i("tagconvertstr", "["+response+"]");
JSONObject jsonResponse = new JSONObject(response);
boolean success = jsonResponse.getBoolean("success");
if (success) {
onSignupSuccess();
} else {
onSignupFailed();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};

RegisterRequest registerRequest = new RegisterRequest(name, email, password, responseListener);
RequestQueue queue = Volley.newRequestQueue(RegisterActivity.this);
queue.add(registerRequest);

/*new android.os.Handler().postDelayed(
new Runnable() {
public void run() {

// On complete call either onSignupSuccess or onSignupFailed
// depending on success
onSignupSuccess();
// onSignupFailed();
progressDialog.dismiss();
}
}, 3000);*/
}

public void onSignupSuccess() {
Toast.makeText(getBaseContext(), "Signup Successful", Toast.LENGTH_LONG).show();
_signupButton.setEnabled(true);
setResult(RESULT_OK, null);
finish();
}

public void onSignupFailed() {
Toast.makeText(getBaseContext(), "Signup Failed", Toast.LENGTH_LONG).show();
_signupButton.setEnabled(true);
}

public boolean validate() {
boolean valid = true;
boolean psisequal;

String name = _nameText.getText().toString();
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
String confirmPassword = _confirmPasswordText.getText().toString();

if (name.isEmpty() || name.length() < 3) {
_nameText.setError("at least 3 characters");
valid = false;
} else {
_nameText.setError(null);
}

if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
_emailText.setError("enter a valid email address");
valid = false;
} else {
_emailText.setError(null);
}

if (password.isEmpty() || password.length() < 4 || password.length() > 10) {
_passwordText.setError("between 4 and 10 alphanumeric characters");
valid = false;
}else {
_passwordText.setError(null);
}

if (password.equals(confirmPassword)){
_confirmPasswordText.setError(null);
psisequal = true;
}else {
_confirmPasswordText.setError("passwords do not match");
valid = false;
psisequal = false;
}

return valid;
}
}


activity_register

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true"
android:background="@color/black">

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="56dp"
android:paddingLeft="24dp"
android:paddingRight="24dp">

<ImageView android:src="@drawable/logo"
android:layout_width="wrap_content"
android:layout_height="72dp"
android:layout_marginBottom="24dp"
android:layout_gravity="center_horizontal" />

<!-- Name Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textColor="#ffffff"
android:textColorHint="#ffffff">
<EditText android:id="@+id/input_name"
android:theme="@style/MyEditTextTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:hint="Trainer Name (Gamer Tag)" />
</android.support.design.widget.TextInputLayout>

<!-- Email Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textColor="#ffffff"
android:textColorHint="#ffffff">
<EditText android:id="@+id/input_email"
android:theme="@style/MyEditTextTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:hint="E-Mail Address" />
</android.support.design.widget.TextInputLayout>

<!-- Password Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textColor="#ffffff"
android:textColorHint="#ffffff">
<EditText android:id="@+id/input_password"
android:theme="@style/MyEditTextTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="Password"/>
</android.support.design.widget.TextInputLayout>

<!-- Confirm Password Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textColor="#ffffff"
android:textColorHint="#ffffff">
<EditText android:id="@+id/input_confirmPassword"
android:theme="@style/MyEditTextTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="Confirm Password"/>
</android.support.design.widget.TextInputLayout>

<!-- Signup Button -->
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_signup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:padding="12dp"
android:text="Create Account"/>

<TextView android:id="@+id/link_login"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Already a member? Login"
android:textColor="#ffffff"
android:gravity="center"
android:textSize="16dip"/>

</LinearLayout>
</ScrollView>


Strings

<resources xmlns:android="http://schemas.android.com/tools">
<string name="app_name">The World of Go</string>
<string name="title_activity_maps">Map</string>
<!--CODE FOR BUTTON OVERLAY-->
<string name="Popular"></string>
<string name="AZ"></string>
<string name="Category"></string>
<string name="NearBy"></string>
<color name="bg_color">#ffffff</color>
<color name="black">#222222</color>
<color name="white">#ffffff</color>
<style name="MyEditTextTheme">
<item name="colorControlNormal">#ffffff</item>
<item name="colorControlActivated">#ffffff</item>
<item name="colorControlHighlight">#ffffff</item>
<item name="colorAccent">@android:color/white</item>
<item name="android:textColor">#ffffff</item>
<item name="android:textColorHint">#ffffff</item> />
</style>

<string name="type_prompt">Choose a Type</string>
<string-array name="type_arrays">
<item>Pokestop</item>
<item>Gym</item>
</string-array>
</resources>

Answer

So here is what I had to do to fix this. I disabled the standard text view of the textEdit by doing the following:

app:passwordToggleEnabled="false"

This will disable the view of the icon to toggle the password visibility. Then What I did was to add an imageView and added my own eye icon to the app:

<ImageView
    android:id="@+id/imageView_registerPasswordVisibility"
    android:layout_width="24dp"
    android:layout_height="24dp"
    android:clickable="true"
    android:src="@drawable/eye"
    android:layout_row="4"
    android:layout_column="1"
    android:foregroundGravity="center_vertical"
    android:layout_gravity="center_vertical" />

I converted my layout to a grid layout and put this image view in the next column to align it to the end of the textEdit, the reason behind this is cause we now show the icon AFTER the textEdit instead of inside the textEdit which where the error validation icon will appear. Doing this will fix the conflict, I handled the imageView to do the same thing as passwordToggle. So here is the entire code for all of that which will also show how to set errors properly on the TextInputLayout if that is what you are using. If not then set errors as you would normally (can be found in standard android documentation):

RegisterActivity.java

public class RegisterActivity extends AppCompatActivity {

    //Setup global variables for all of the user interface items.
    @InjectView(R.id.wrapper_registerPassword)
    TextInputLayout _registerPasswordWrapper; /*this is only needed for when you use TextInputLayout that gives us the ability to have animated hints by default. If you are ONLY using editText then you will not need the code for this wrapper.*/
    @InjectView(R.id.editText_registerPasswordInput)
    EditText _registerPasswordInput; /*This is to access text that was typed in the editText*/
    @InjectView(R.id.imageView_registerPasswordVisibility)
    ImageView _registerPasswordVisibility; /*This is used for our image that we will be adding listeners for to do speacial features when the image is pressed. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        ButterKnife.inject(this);

        /*Set a listener for the password view image to display the text inside the password text
        field for when the image is pressed.*/
        _registerPasswordVisibility.setOnTouchListener(mPasswordVisibleTouchListener);
    }

    /*Listener for the toggle password icon.*/
    private View.OnTouchListener mPasswordVisibleTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            final boolean isOutsideView = event.getX() < 0 ||
                    event.getX() > v.getWidth() ||
                    event.getY() < 0 ||
                    event.getY() > v.getHeight();

            // change input type will reset cursor position, so we want to save it
            final int cursor = _registerPasswordInput.getSelectionStart();

            if (isOutsideView || MotionEvent.ACTION_UP == event.getAction())
            /*This will make the field display dots as a password text field should look like.*/
                _registerPasswordInput.setInputType( InputType.TYPE_CLASS_TEXT |
                        InputType.TYPE_TEXT_VARIATION_PASSWORD);
            else
            /*This will make the text in the password text field visibile while we are pressing down on our image.*/
                _registerPasswordInput.setInputType( InputType.TYPE_CLASS_TEXT |
                        InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);

            _registerPasswordInput.setSelection(cursor);
            return true;
        }
    };

    public boolean validate() {
        boolean valid = true;

        //Obtain user's entered in credentials to validate them.
        String password = _registerPasswordInput.getText().toString();

        //Password validation.
        if (password.isEmpty() || password.length() < 8 || password.length() > 30) {
            _registerPasswordWrapper.setError("Please provide a stronger password.\n" +
                    "•Password must be the following:\n" +
                    "•At least 8 characters");
            _registerPasswordWrapper.setErrorEnabled(true);
            valid = false;
        }else {
            _registerPasswordWrapper.setError(null);
        }

        return valid;
    }
}

activity_register.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:android.support.design="http://schemas.android.com/tools"
        android:fitsSystemWindows="true"
        android:background="@color/black">

        <!-- Start of Grid Layout -->
        <GridLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="56dp"
            android:paddingLeft="24dp"
            android:paddingRight="24dp"
            android:orientation="vertical">

            <!-- Password Text Field -->
            <android.support.design.widget.TextInputLayout
            android:id="@+id/wrapper_registerPassword"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            android:textColor="#ffffff"
            app:passwordToggleEnabled="false"
            android:textColorHint="#ffffff"
            android:layout_column="0"
            android:layout_row="4"
            android:layout_gravity="fill_horizontal">
            <android.support.design.widget.TextInputEditText
                android:id="@+id/editText_registerPasswordInput"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLength="30"
                android:inputType="textPassword"
                android:hint="Password" />
        </android.support.design.widget.TextInputLayout>

        <!-- Password Toggle Icon for Password field -->
        <ImageView
            android:id="@+id/imageView_registerPasswordVisibility"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:clickable="true"
            android:src="@drawable/eye"
            android:layout_row="4"
            android:layout_column="1"
            android:foregroundGravity="center_vertical"
            android:layout_gravity="center_vertical" />

    </GridLayout>
</ScrollView>

I hope this helps out some people, if anyone has anymore questions please let me know and ill help out to the best of my abilities!

Comments