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>



相关文章
|
4月前
|
存储 消息中间件 人工智能
【03】AI辅助编程完整的安卓二次商业实战-本地构建运行并且调试-二次开发改注册登陆按钮颜色以及整体资源结构熟悉-优雅草伊凡
【03】AI辅助编程完整的安卓二次商业实战-本地构建运行并且调试-二次开发改注册登陆按钮颜色以及整体资源结构熟悉-优雅草伊凡
167 3
|
8月前
|
数据库 Android开发
Android使用EditText+Listview实现搜索效果(使用room模糊查询)
本文介绍如何在Android中使用EditText与ListView实现搜索功能,并结合Room数据库完成模糊查询。主要内容包括:Room的模糊查询语句(使用`||`代替`+`号)、布局美化(如去除ListView分割线和EditText下划线)、EditText回车事件监听,以及查询逻辑代码示例。此外,还提供了相关扩展文章链接,帮助读者深入了解ListView优化、动态搜索及Room基础操作。
576 65
|
8月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
569 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
4月前
|
存储 消息中间件 人工智能
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
152 11
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
|
8月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
157 0
|
8月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
394 65
Android自定义view之网易云推荐歌单界面
|
8月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
749 84
|
8月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
246 3
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
190 2