A comprehensive analysis of Android in the EditText input implementation of the monitoring method _android

Source: Internet
Author: User
Tags gettext

The Android Design support package provides a hint that the input characters has been displayed, and is now starting to be used in more applications; these Android apps The different ways they use when displaying their error cues often make people feel very discordant.
That is, the error message that is always displayed is around the edittext in the textinputlayout. It is also, as a reward, provides a material design style in which lively floating tags are often the most boring part of an APP's user experience.
Here's how to create a generic, reusable component in your input form to implement all field validation. Because you want to hide the error message when the user corrects the wrong input. We can implement validation by using Textwatchers.

Unfortunately, in the latest support library (23.1), once you hide the error prompts and let them show again, there is a bug. So this example is based on this 23.0.1 support library. At this point I have a love-hate relationship with the support library--every time a new version is released, I'm like a child at Christmas: I rushed downstairs to see what the new toy was from Santa Claus, but when I found out he was bringing new toys, my new toy train lacked some parts, He also broke some of my favorite toys, and put the chimney of soot on the stall.

To create our generic class
Put aside my little complaints, let's create an abstract Errortextwatcher class that implements the Textwatcher interface. For this simple example, I'd like to say that our textwatcher always comes with textinputlayout, and it can display a simple error message. Your user experience design team may want to display a different error-such as: "Password cannot be empty", "password must contain at least one number", "Please enter at least 4 characters", and so on. -but for simplicity's sake, I'll show you how to implement a simple message for each textwatcher.

Public abstract class Errortextwatcher implements Textwatcher {

  private textinputlayout mtextinputlayout;
  Private String errormessage;

  Protected Errortextwatcher (@NonNull final textinputlayout textinputlayout, @NonNull final String errormessage) {
    This.mtextinputlayout = textinputlayout;
    This.errormessage = errormessage;
  }

I also added some general methods to this abstract class:

Public Final Boolean Haserror () {return
  mtextinputlayout.geterror ()!= null;
}

Protected String Getedittextvalue () {return
  mtextinputlayout.getedittext (). GetText (). toString ();
}

I also want all my errortextwatchers to implement the Validate () method, which returns true if the input is correct, so that you can simply show or hide the error:

Public abstract Boolean validate ();

protected void ShowError (final Boolean error) {
  if (!error) {
    mtextinputlayout.seterror (null);
    Mtextinputlayout.seterrorenabled (false);
  else {
    if (!errormessage.equals (Mtextinputlayout.geterror ()) {
      //Stop The flickering that happens when setting The same error message multiple times
      mtextinputlayout.seterror (errormessage);
    }
    Mtextinputlayout.requestfocus ();
  }


In my code, this library has another feature here: In my opinion, by setting the error enabled to False, you should be able to hide the error hint, but this will make the EditText underline still display the incorrect color, so you need to set the error prompt to empty, You also need to restore the underlined color. Similarly, if you keep setting the same error string, the error message will flicker as the animation continues, so you only have to rewrite it when the error prompts for a new value.

Finally, when the focus is on the edittext in Textwatcher, I have a bit of naughty request--when you see how I validate the input form, I hope you understand why I do it, but for your needs, you might want to move this logic somewhere else.

As an additional optimization, I found that I could implement all my logic within the Textwatcher interface of the OnTextChanged method, so I added two empty methods to Beforetextchanged and Aftertextchanged's parent classes.

Minimum length validation
now, let's take a concrete example of this class. A common use case is a character that requires at least X for the input field. So let's create a minimumlengthtextwatcher. It comes with a minimum length value, and of course, in the parent class, I also need textinputlayout and message. Also, I don't want to keep telling the user that they need to enter X characters before they can input it--it would be a bad user experience--so we should start showing the error when the user has exceeded the minimum limit character. (Translator Note: It can be understood that when the user enters a length that exceeds the minimum limit character, the user deletes part of the character, and if it is less than the minimum limit character, it will show an error, so that it can be understood)

public class Minimumlengthtextwatcher extends Errortextwatcher {

  private final int mminlength;
  Private Boolean mreachedminlength = false;

  Public Minimumlengthtextwatcher (Final textinputlayout textinputlayout, final int minlength) {This
    ( Textinputlayout, minlength, r.string.error_too_few_characters);

  Public Minimumlengthtextwatcher (Final textinputlayout textinputlayout, final int minlength, @StringRes final int errormessage) {
    super (Textinputlayout, String.Format (Textinputlayout.getcontext (). getString (ErrorMessage), minlength));
    This.mminlength = minlength;
  }

Here are two construction methods: one with the default message and one that you can create a more specific value for a particular text field. Because we want to support localization, we take the Android string resource file instead of the hard-coded string value.

Our textual changes and validation methods are now implemented as simple as the following:

@Override public
void ontextchanged (final charsequence text ...) {
  if (mreachedminlength) {
    validate ();
  }
  if (Text.length () >= mminlength) {
    mreachedminlength = true;
  }
}

@Override public
Boolean validate () {
  mreachedminlength = true;//It is true but now we want to force The error to be shown
  ShowError (Getedittextvalue (). Length () < mminlength);
  return!haserror ();
}

You will notice that once the validation method is textwatcher in the system, it will display an error. I think this applies to most situations, but you might want to introduce a setter method to reset this behavior in some cases.

You now need to add textwatcher to your textinputlayout and then create views in your activity or Fragment. Just like this:

Mpasswordview = (textinputlayout) Findviewbyid (r.id.password_text_input_layout);
Mvalidpasswordtextwatcher = new Minimumlengthtextwatcher (Mpasswordview, Getresources (). Getinteger (R.integer.min_ Length_password));
Mpasswordview.getedittext (). Addtextchangedlistener (Mvalidpasswordtextwatcher);

Then, in the appropriate location of your code, you can check whether a field is valid:

Boolean isValid = Mvalidpasswordtextwatcher.validate ();
If the password is invalid, the View automatically gets the focus and scrolls the screen here.

Verifying e-mail addresses
Another common validation use case is to check whether the e-mail address is valid. I can easily write an entire article about verifying email addresses with regular expressions, but since this is often controversial, I've separated the logic of message validation from Textwatcher itself. The sample project contains testable emailaddressvalidator that you can use, or you can use the logic you want to implement.

Now that I've separated the email verification logic, Validemailtextwatcher is very similar to Minimumlengthtextwatcher.

public class Validemailtextwatcher extends Errortextwatcher {

  private final emailaddressvalidator mvalidator = new Em Ailaddressvalidator ();
  Private Boolean mvalidated = false;


  Public Validemailtextwatcher (@NonNull final textinputlayout textinputlayout) {This
    (textinputlayout, R.string.error_invalid_email);
  }

  Public Validemailtextwatcher (@NonNull final textinputlayout textinputlayout, @StringRes final int errormessage) {
    Super (Textinputlayout, Textinputlayout.getcontext (). getString (errormessage));

  @Override public
  void ontextchanged (...) {
    if (mvalidated) {
      validate ();
    }
  }

  @Override public
  Boolean validate () {
    showerror (!mvalidator.isvalid (Getedittextvalue ()));
    Mvalidated = true;
    return!haserror ();
  }

The way this textwatcher is implemented within our activity or Fragment is very much like the previous one:

Memailview = (textinputlayout) Findviewbyid (r.id.email_text_input_layout);
Mvalidemailtextwatcher = new Validemailtextwatcher (memailview);
Memailview.getedittext (). Addtextchangedlistener (Mvalidemailtextwatcher);

Put it together.
for form registration or login, you usually validate all fields before submitting to your API. Because we require attention to the failure validation of any views in Textwatcher. I usually verify all the view from the bottom up. This way, the application displays all errors that need to be corrected, and then jumps to the first error-entered text on the form. For example:

Private Boolean Allfieldsarevalid () {
  /**
   * Since The text watchers automatically focus in erroneous fields, do th  EM in reverse, so the "the", "the", "the", "gets focus * &=", "" "
   easiest construct to decipher But it ' s a lot more concise. It just means that once it's false it doesn ' t get set to True
   * * * *
  boolean isValid = Mvalidpasswordtextwatcher.vali Date ();
  IsValid &= mvalidemailtextwatcher.validate ();
  return isValid;
}

You can find examples of all the above code in GITHUB[1]. This is a branch on the Clearableedittext, and I am based on having your edittext erase all the code on this blog (2), but it is the same on the standard edittext. It also includes some more tips and bug handling that I don't have time to mention here.

Although I show only two examples of textwatcher, I want you to see how simple this is, and you can now add other textwatcher to add different validation methods to any text input and request validation and reuse in your APP.

An input box control with a purge function clearedittext
here to bring you a very useful small control clearedittext, is in the Android system input box to the right to add a small icon, click on the small icon to clear the contents of the input box, iOS above directly set a property can achieve this function, But Android native EditText does not have this feature, so in order to implement this feature we need to rewrite edittext, and then we'll take you to this little function
We know that we can set the picture for our input box up and down, so we can use the attribute android:drawableright to set our delete small icons, as shown in

I set the left and right side of the picture, if we can set the right side of the picture to monitor, click on the right side of the picture to clear the contents of the input box and hide the deletion icon, this kind of small function will be solved, but Android does not allow us to the right small icon plus the function Is this the way you find out this road is not, in fact, we may simulate the click event, using the input box Ontouchevent () method to simulate,
When we touch lift (that is, ACTION_UP) the range is greater than the left side of the input box to the left of the clear icon, small and the left side of the input box to clear the distance to the right of the picture, we think is click to clear the picture, of course, I do not consider the vertical direction, as long as the removal of small icons on the monitor, The other is all right, I'll put the code up, under the explanation

Package com.example.clearedittext; 
Import Android.content.Context; 
Import android.graphics.drawable.Drawable; 
Import android.text.Editable; 
Import Android.text.TextWatcher; 
Import Android.util.AttributeSet; 
Import android.view.MotionEvent; 
Import Android.view.View; 
Import Android.view.View.OnFocusChangeListener; 
Import android.view.animation.Animation; 
Import Android.view.animation.CycleInterpolator; 
Import android.view.animation.TranslateAnimation; 
 
Import Android.widget.EditText; 
   public class Clearedittext extends EditText implements Onfocuschangelistener, Textwatcher {/** * reference to delete button  
  * * Private drawable mcleardrawable; 
  
  /** * Control whether has the focus * * Private Boolean Hasfoucs;  
  Public Clearedittext {This (context, NULL); "Public clearedittext" (context context, AttributeSet attrs) {//It is also important to construct the method, without which many attributes cannot be defined in XML (conte XT, Attrs, Android.  
  R.attr.edittextstyle); } public Clearedittext(Context, AttributeSet attrs, int defstyle) 
    {Super (context, attrs, Defstyle); 
  Init (); private void Init () {//Get edittext drawableright, if not set we use the default picture mcleardrawable = Getcompounddraw  
    Ables () [2]; 
      if (mcleardrawable = = null) {//throw new NullPointerException ("You can add drawableright attributes in XML");  
    mcleardrawable = Getresources (). getdrawable (R.drawable.delete_selector);  
    Mcleardrawable.setbounds (0, 0, mcleardrawable.getintrinsicwidth (), Mcleardrawable.getintrinsicheight ());  
    The default setting hides the icon setcleariconvisible (false);  
    Set focus-Changing listening setonfocuschangelistener (this);  
  Set the input box to change the content of the listening addtextchangedlistener (this); 
   /** * Because we can not set the Click event directly to EditText, so we use to remember the position we pressed to simulate the click event * when we press the position at the edittext width-the icon to the right of the control spacing-the width of the icon and  
    * EditText Width-The distance between the icon and the right side of the control if we click on the icon, the vertical direction is not considered * * @Override public boolean ontouchevent (Motionevent event) { if (EVENT.GEtaction () = = motionevent.action_up) {if (Getcompounddrawables () [2]!= null) {Boolean touchable = even T.getx () > (GetWidth ()-gettotalpaddingright ()) && (Event.getx () < (getwidth ()-Getpaddingri 
         
        Ght ())); 
        if (touchable) {This.settext (""); 
  }} return Super.ontouchevent (event); /** * When Clearedittext focus changes, determine the string length set clear icon display and hide/@Override public void Onfocuschange (View V, 
    Boolean hasfocus) {this.hasfoucs = Hasfocus;  
    if (hasfocus) {setcleariconvisible (GetText (). Length () > 0);  
    else {setcleariconvisible (false);  }/** * Set clear icon display and hide, call setcompounddrawables for EditText draw up * @param visible/protected void  
    Setcleariconvisible (Boolean visible) {drawable right = visible? Mcleardrawable:null; Setcompounddrawables (Getcompounddrawables () [0], Getcompounddrawables() [1], right, Getcompounddrawables () [3]);  /** * The method of callback when the contents of the input box is changed * * @Override public void ontextchanged (charsequence s, int start, 
        int count, int after) {if (Hasfoucs) {setcleariconvisible (s.length () > 0);  
      
  @Override public void beforetextchanged (charsequence s, int start, int count, int after) { 
  @Override public void aftertextchanged (Editable s) {}/** * Set shaking animation * * 
  public void Setshakeanimation () {this.setanimation (Shakeanimation (5)); /** * Shaking animation * @param counts 1 seconds to shake how many under * @return/public static Animation Shakeanimation 
    T counts) {Animation translateanimation = new Translateanimation (0, 10, 0, 0); 
    Translateanimation.setinterpolator (New Cycleinterpolator (counts)); 
    Translateanimation.setduration (1000); 
  return translateanimation; 

 } 
  
  
}

Setcleariconvisible () method, set the way to hide and display the purge icon, we are not here to call the Setvisibility () method, Setvisibility () This method is for view, We can call Setcompounddrawables (drawable left, drawable top, drawable right, drawable bottom) to set up and down icons
Setonfocuschangelistener (this) to set the focus of the input box to change the listener, if the input box has the focus, we determine whether the value of the input box is empty, empty to hide the clear icon, otherwise the display
Addtextchangedlistener (this) set the content of the input box to change the listening, in fact, very simple, when the contents of the input box changes, we need to deal with the display and hide the small icon, the content length is not 0 we will show, no is on the hidden, But this need to enter the box has the focus we change the show or hide, why need focus, such as we have a login interface, we saved the user name and password, in the Landing Interface OnCreate (), we put our saved password displayed in the Username input box and password input box, The contents of the input box changed, resulting in the User name input box and password in the box to clear the small icons are shown, this is obviously not the effect we want, so added a whether there is a focus on the judgment
Setshakeanimation (), this method is the input frame left and right jitter method, before I saw a similar function in an application, when the user name error, the input box where the jitter, feeling quite fun, in fact, is mainly used to a mobile animation, and then set the animation rate of change for the sine curve

Next we'll use it, the layout of the activity, two of our custom input boxes, a button

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http:// Schemas.android.com/tools "android:layout_width=" match_parent "android:layout_height=" Match_parent "android:backg" round= "#95CAE4" > <com.example.clearedittext.clearedittext android:id= "@+id/username" android:layout _margintop= "60DP" android:layout_width= "fill_parent" android:background= "@drawable/login_edittext_bg" Andr 
    oid:drawableleft= "@drawable/icon_user" android:layout_marginleft= "10dip" android:layout_marginright= "10dip" Android:singleline= "true" android:drawableright= "@drawable/delete_selector" android:hint= "Enter user name" Android:l ayout_height= "Wrap_content" > </com.example.clearedittext.ClearEditText> <com.example.clearedittext. Clearedittext android:id= "@+id/password" android:layout_marginleft= "10dip" android:layout_marginright= "10di 
  P "android:layout_margintop=" 10dip "  android:drawableleft= "@drawable/account_icon" android:hint= "Enter password" android:singleline= "true" ANDROID:PASSW Ord= "true" android:drawableright= "@drawable/delete_selector" android:layout_width= "Fill_parent" Android:lay out_height= "Wrap_content" android:layout_below= "@id/username" android:background= "@drawable/login_edittext_bg" & 
  Gt </com.example.clearedittext.ClearEditText> <button android:id= "@+id/login" android:layout_width= "F" Ill_parent "android:layout_height=" wrap_content "android:layout_marginleft=" 10dip "Android:layout_marginrig ht= "10dip" android:background= "@drawable/login_button_bg" android:textsize= "18sp" android:textcolor= "@andro Id:color/white "android:layout_below=" @+id/password "android:layout_margintop=" 25DP "android:text=" Login "/&gt 
 
; 
 </RelativeLayout>

Then is the interface code writing, mainly testing the input box around the shaking, relatively simple

Package com.example.clearedittext; 
Import android.app.Activity; 
Import Android.os.Bundle; 
Import Android.text.TextUtils; 
Import Android.view.View; 
Import Android.view.View.OnClickListener; 
Import Android.widget.Button; 
 
Import Android.widget.Toast; 
 
  public class Mainactivity extends activity {private Toast mtoast; 
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
     
    Setcontentview (R.layout.activity_main); 
    Final Clearedittext username = (clearedittext) Findviewbyid (r.id.username); 
     
    Final Clearedittext password = (clearedittext) Findviewbyid (R.id.password);  (Button) Findviewbyid (r.id.login). Setonclicklistener (New Onclicklistener () {@Override public void OnClick (View v) {if (Textutils.isempty (Username.gettext ())) {//set sloshing Username.setshakeanima 
          tion (); 
          Set prompt Showtoast ("User name cannot be empty"); 
        Return }
         
        if (Textutils.isempty (Password.gettext ())) {password.setshakeanimation (); 
          Showtoast ("Password cannot be blank"); 
        Return 
  } 
      } 
    }); 
      /** * Display Toast message * @param msg/private void Showtoast (String msg) {if (mtoast = = null) { 
    Mtoast = Toast.maketext (This, MSG, toast.length_short); 
    }else{Mtoast.settext (msg); 
  } mtoast.show (); 

 } 
 
 
}

Run the project, such as the picture, tragedy, no animation effect, let's just like this, you are not also want to add it to your project, hurry up!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.