Android自定义View示例(一)—带有删除按钮的EditText

简介: MainActivity如下: package cc.textview5;import android.os.Bundle;import android.


MainActivity如下:

package cc.textview5;
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;
import android.app.Activity;
/**
 * Demo描述:
 * 自定义控件实现带清除功能的EditText
 * 
 * 学习资料:
 * http://blog.csdn.net/xiaanming/article/details/11066685
 * 
 * Thank you very much
 */
public class MainActivity extends Activity {
    private CleanableEditText mUserNameCleanableEditText;
    private CleanableEditText mPassWordCleanableEditText;
    private Button mLoginButton;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		init();
	}
	
	private void init(){
		mUserNameCleanableEditText=(CleanableEditText) findViewById(R.id.userNameEditText);
		mPassWordCleanableEditText=(CleanableEditText) findViewById(R.id.passwordEditText);
		mLoginButton=(Button) findViewById(R.id.loginButton);
		mLoginButton.setOnClickListener(new OnClickListenerImpl());
	}
    
	private class OnClickListenerImpl implements OnClickListener {
		@Override
		public void onClick(View view) {
			if (TextUtils.isEmpty(mUserNameCleanableEditText.getText())) {
				mUserNameCleanableEditText.setShakeAnimation();
				Toast.makeText(MainActivity.this, "请输入用户名", Toast.LENGTH_SHORT).show();
			}

			if (TextUtils.isEmpty(mPassWordCleanableEditText.getText())) {
				mPassWordCleanableEditText.setShakeAnimation();
				Toast.makeText(MainActivity.this, "请输入密码", Toast.LENGTH_SHORT).show();
			}
		}

	}
	

}

CleanableEditText如下:

package cc.textview5;

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.animation.Animation;
import android.view.animation.CycleInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.EditText;
/**
 * 在焦点变化时和输入内容发生变化时均要判断是否显示右边clean图标
 */
public class CleanableEditText extends EditText {
    private Drawable mRightDrawable;
    private boolean isHasFocus;
	
	public CleanableEditText(Context context) {
		super(context);
		init();
	}
	public CleanableEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public CleanableEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
	private void init(){
		//getCompoundDrawables:
		//Returns drawables for the left, top, right, and bottom borders.
		Drawable [] drawables=this.getCompoundDrawables();
		
		//取得right位置的Drawable
		//即我们在布局文件中设置的android:drawableRight
        mRightDrawable=drawables[2];	
	   
        //设置焦点变化的监听
        this.setOnFocusChangeListener(new FocusChangeListenerImpl());
        //设置EditText文字变化的监听
        this.addTextChangedListener(new TextWatcherImpl());
        //初始化时让右边clean图标不可见
        setClearDrawableVisible(false);
	}
	
	
	/**
	 * 当手指抬起的位置在clean的图标的区域
	 * 我们将此视为进行清除操作
	 * getWidth():得到控件的宽度
	 * event.getX():抬起时的坐标(改坐标是相对于控件本身而言的)
	 * getTotalPaddingRight():clean的图标左边缘至控件右边缘的距离
	 * getPaddingRight():clean的图标右边缘至控件右边缘的距离
	 * 于是:
	 * getWidth() - getTotalPaddingRight()表示:
	 * 控件左边到clean的图标左边缘的区域
	 * getWidth() - getPaddingRight()表示:
	 * 控件左边到clean的图标右边缘的区域
	 * 所以这两者之间的区域刚好是clean的图标的区域
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_UP:
			
			boolean isClean =(event.getX() > (getWidth() - getTotalPaddingRight()))&&
					         (event.getX() < (getWidth() - getPaddingRight()));
			if (isClean) {
				setText("");
			}
			break;

		default:
			break;
		}
		return super.onTouchEvent(event);
	}
	
	private class FocusChangeListenerImpl implements OnFocusChangeListener{
		@Override
		public void onFocusChange(View v, boolean hasFocus) {
             isHasFocus=hasFocus;
             if (isHasFocus) {
            	 boolean isVisible=getText().toString().length()>=1;
            	 setClearDrawableVisible(isVisible);
			} else {
                 setClearDrawableVisible(false);
			}
		}
		
	}
	
	//当输入结束后判断是否显示右边clean的图标
    private class TextWatcherImpl implements TextWatcher{
		@Override
		public void afterTextChanged(Editable s) {
			 boolean isVisible=getText().toString().length()>=1;
        	 setClearDrawableVisible(isVisible);
		}

		@Override
		public void beforeTextChanged(CharSequence s, int start, int count,int after) {
			
		}

		@Override
		public void onTextChanged(CharSequence s, int start, int before,int count) {
			
		}
    	
    }	
    
    //隐藏或者显示右边clean的图标
	protected void setClearDrawableVisible(boolean isVisible) {
		Drawable rightDrawable;
		if (isVisible) {
			rightDrawable = mRightDrawable;
		} else {
			rightDrawable = null;
		}
		//使用代码设置该控件left, top, right, and bottom处的图标
		setCompoundDrawables(getCompoundDrawables()[0],getCompoundDrawables()[1], 
				             rightDrawable,getCompoundDrawables()[3]);
	} 

	// 显示一个动画,以提示用户输入
	public void setShakeAnimation() {
		this.setAnimation(shakeAnimation(5));
	}

	//CycleTimes动画重复的次数
	public Animation shakeAnimation(int CycleTimes) {
		Animation translateAnimation = new TranslateAnimation(0, 10, 0, 10);
		translateAnimation.setInterpolator(new CycleInterpolator(CycleTimes));
		translateAnimation.setDuration(1000);
		return translateAnimation;
	}

}

main.xml如下:

<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:paddingLeft="20dip"
    android:paddingRight="20dip"
    >

    <cc.textview5.CleanableEditText
        android:id="@+id/userNameEditText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="username"
        android:layout_marginTop="30dip"
        android:drawableLeft="@drawable/icon_user"
        android:drawableRight="@drawable/clean_selector"
         />
    
     <cc.textview5.CleanableEditText
        android:id="@+id/passwordEditText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="password"
        android:password="true"
        android:layout_marginTop="100dip"
        android:drawableLeft="@drawable/account_icon"
        android:drawableRight="@drawable/clean_selector"
         />
     
     <Button
         android:id="@+id/loginButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Login"
        android:layout_marginTop="155dip"
         />

</RelativeLayout>



相关文章
|
2天前
|
存储 消息中间件 缓存
Android应用开发:实现自定义View的高效绘制
【5月更文挑战第12天】 在Android开发中,创建高性能的自定义视图是一项挑战,它要求开发者深入理解Android的绘图机制以及UI渲染过程。本文将探讨如何优化自定义View的绘制流程,减少不必要的重绘和布局计算,以提升应用的响应速度和流畅度。我们将介绍几种关键策略,包括利用硬件加速、缓存绘制内容和使用高效的数据结构来存储视图状态。通过实例分析和性能对比,读者将学会如何在自己的应用中运用这些技巧,从而打造出更加流畅和响应迅速的用户界面。
|
4天前
|
XML Android开发 数据格式
Android下自定义Button样式
Android下自定义Button样式
10 3
|
5天前
|
XML Java Android开发
如何美化android程序:自定义ListView背景
如何美化android程序:自定义ListView背景
|
5天前
|
搜索推荐 Android开发
自定义Android标题栏TitleBar布局
自定义Android标题栏TitleBar布局
|
7天前
|
Android开发
Android 高通平台集成无源码apk示例
Android 高通平台集成无源码apk示例
16 0
|
7天前
|
调度 Android开发
Android9底部导航栏出现空白按钮问题分析
Android9底部导航栏出现空白按钮问题分析
12 0
|
21天前
|
Android开发 芯片
Android源代码定制:移除无用lunch|新建lunch|自定义customize.mk
Android源代码定制:移除无用lunch|新建lunch|自定义customize.mk
26 3
|
21天前
|
移动开发 Java Unix
Android系统 自动加载自定义JAR文件
Android系统 自动加载自定义JAR文件
45 1
|
21天前
|
Shell Android开发 开发者
Android系统 自定义动态修改init.custom.rc
Android系统 自定义动态修改init.custom.rc
38 0
|
11天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。