Android的輸入框中加入清除按鈕
阿新 • • 發佈:2019-01-02
1、實現自己的EditText
package com.ming.doustec.clearableedittextdemo; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * Created by ds03 on 2015/9/11. */ public class ClearableEditText extends AppCompatEditText implements View.OnTouchListener, View.OnFocusChangeListener, TextWatcher { private Drawable mClearTextIcon; private OnFocusChangeListener mOnFocusChangeListener; private OnTouchListener mOnTouchListener; public ClearableEditText(Context context) { super(context); init(context); } public ClearableEditText(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ClearableEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context){ //封裝drawable物件 Drawable drawable = ContextCompat.getDrawable(context,R.drawable.abc_ic_clear_mtrl_alpha); Drawable wrappedDrawable = DrawableCompat.wrap(drawable); //簡單著色 DrawableCompat.setTint(wrappedDrawable, getCurrentHintTextColor()); mClearTextIcon = wrappedDrawable; //設定寬高 mClearTextIcon.setBounds(0, 0, mClearTextIcon.getIntrinsicHeight(), mClearTextIcon.getIntrinsicWidth()); setClearIconVisible(false); super.setOnTouchListener(this); super.setOnFocusChangeListener(this); addTextChangedListener(this); } private void setClearIconVisible(final boolean visible) { mClearTextIcon.setVisible(visible, false); final Drawable[] compoundDrawables = getCompoundDrawables(); //在edittext右側設定圖示 setCompoundDrawables( compoundDrawables[0], compoundDrawables[1], visible ? mClearTextIcon : null, compoundDrawables[3]); } @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { setClearIconVisible(getText().length() > 0); } else { setClearIconVisible(false); } if (mOnFocusChangeListener != null) { mOnFocusChangeListener.onFocusChange(v, hasFocus); } } @Override public boolean onTouch(View v, MotionEvent event) { final int x = (int) event.getX(); if (mClearTextIcon.isVisible() && x > getWidth() - getPaddingRight() - mClearTextIcon.getIntrinsicWidth()) { if (event.getAction() == MotionEvent.ACTION_UP) { setError(null); setText(""); } return true; } return mOnTouchListener != null && mOnTouchListener.onTouch(v, event); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } @Override public final void onTextChanged(final CharSequence s, final int start, final int before, final int count) { if (isFocused()) { setClearIconVisible(s.length() > 0); } } @Override public void setOnFocusChangeListener(final OnFocusChangeListener onFocusChangeListener) { mOnFocusChangeListener = onFocusChangeListener; } @Override public void setOnTouchListener(final OnTouchListener onTouchListener) { mOnTouchListener = onTouchListener; } }
2、佈局
<LinearLayout 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:gravity="center_horizontal" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".LoginActivity"> <!-- Login progress --> <ProgressBar android:id="@+id/login_progress" style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:visibility="gone" /> <ScrollView android:id="@+id/login_form" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/email_login_form" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.design.widget.TextInputLayout android:id="@+id/email_text_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.ming.doustec.clearableedittextdemo.ClearableEditText android:id="@+id/email" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/prompt_email" android:imeOptions="flagNoExtractUi" android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/password_text_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.ming.doustec.clearableedittextdemo.ClearableEditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="sans-serif" android:hint="@string/prompt_password" android:imeActionId="@+id/login" android:imeActionLabel="@string/action_sign_in_short" android:imeOptions="flagNoFullscreen|actionUnspecified" android:inputType="textPassword" android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/email_sign_in_button" style="?android:textAppearanceSmallInverse" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="@string/action_sign_in" android:textStyle="bold" /> </LinearLayout> </ScrollView> </LinearLayout>
3、LoginActivity
package com.ming.doustec.clearableedittextdemo;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.TextView;
public class LoginActivity extends AppCompatActivity {
/**
* A dummy authentication store containing known user names and passwords.
* TODO: remove after connecting to a real authentication system.
*/
private static final String[] DUMMY_CREDENTIALS = new String[]{
" [email protected]:hello", "[email protected]:world"
};
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
// UI references.
private TextInputLayout mEmailView;
private TextInputLayout mPasswordView;
private View mProgressView;
private View mLoginFormView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setTitle(R.string.action_sign_in_short);
// Set up the login form.
mEmailView = (TextInputLayout) findViewById(R.id.email_text_input_layout);
mPasswordView = (TextInputLayout) findViewById(R.id.password_text_input_layout);
mPasswordView.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});
final Button emailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
emailSignInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
attemptLogin();
}
});
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
}
@Override
protected void onResume() {
super.onResume();
if (!getResources().getBoolean(R.bool.is_tablet) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
getSupportActionBar().hide();
} else {
getSupportActionBar().show();
}
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
// Reset errors.
mEmailView.setErrorEnabled(false);
mPasswordView.setErrorEnabled(false);
// Store values at the time of the login attempt.
String email = mEmailView.getEditText().getText().toString();
String password = mPasswordView.getEditText().getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password, if the user entered one.
if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!isEmailValid(email)) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);
mAuthTask = new UserLoginTask(email, password);
mAuthTask.execute((Void) null);
}
}
private boolean isEmailValid(String email) {
//TODO: Replace this with your own logic
return email.contains("@");
}
private boolean isPasswordValid(String password) {
//TODO: Replace this with your own logic
return password.length() > 4;
}
/**
* Shows the progress UI and hides the login form.
*/
public void showProgress(final boolean show) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
private final String mEmail;
private final String mPassword;
UserLoginTask(String email, String password) {
mEmail = email;
mPassword = password;
}
@Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
// Simulate network access.
Thread.sleep(2000);
} catch (InterruptedException e) {
return false;
}
for (String credential : DUMMY_CREDENTIALS) {
String[] pieces = credential.split(":");
if (pieces[0].equals(mEmail)) {
// Account exists, return true if the password matches.
return pieces[1].equals(mPassword);
}
}
// TODO: register the new account here.
return true;
}
@Override
protected void onPostExecute(final Boolean success) {
mAuthTask = null;
showProgress(false);
if (success) {
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
@Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
}