实际开发中经常会遇到输入框,各种不同的需求,在一般情况下,清除内容,以及密码可见与不可见基本很常见,那么不废话直接上代码!

在res\values\attrs.xml中

.java

import android.animation.ObjectAnimator;

import android.animation.ValueAnimator;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Rect;

import android.graphics.RectF;

import android.os.Build;

import android.text.InputType;

import android.util.AttributeSet;

import android.util.Property;

import android.view.MotionEvent;

import android.view.animation.Animation;

import android.view.animation.CycleInterpolator;

import android.view.animation.TranslateAnimation;

import androidx.annotation.Nullable;

import androidx.appcompat.widget.AppCompatEditText;

import com.chaian.phone.imlibrary.R;

/**

* 自定义可带清除、密码显示不显示的输入框

*/

public class SeniorEditText extends AppCompatEditText {

/**

* 边框样式

*/

private static final String STYLE_RECT = "rectangle";//矩形

private static final String STYLE_ROUND_RECT = "roundRect";//圆角矩形

private static final String STYLE_HALF_RECT = "halfRect";//半矩形

private static final String STYLE_ANIMATOR = "animator";//动画特效

private static final int DEFAULT_ROUND_RADIUS = 20;//圆角矩形圆角度

private static final int ANIMATOR_TIME = 200;//动画时间

private static final int DEFAULT_FOCUSED_STROKE_WIDTH = 8;//获取到焦点的边框宽

private static final int DEFAULT_UNFOCUSED_STROKE_WIDTH = 4;//未获取焦点的边框宽

private static final int DEFAULT_STYLE_COLOR = Color.RED;//边框默认颜色

//按钮间隔

private int visible_res_padding = 0;

//按钮宽度

private int visible_res_width = 0;

//右内边距

private int mTextPaddingRight;

//需要显示的drawable 资源id

private int clear_res_id = 0;

private int visible_res_id = 0;

private int invisible_res_id = 0;

//需要显示的bitmap---通过drawable 资源id来

private Bitmap clear_bitmap;

private Bitmap visible_bitmap;

private Bitmap invisible_bitmap;

private String edit_border_style = "";

private int edit_border_color = -1;

//出现和消失动画

private ValueAnimator show_animator;

private ValueAnimator dismiss_animator;

//状态值

private boolean clear_image_isShow = false;

private boolean show_password_image_isShow = false;

private boolean dismiss_password_image_isShow = false;

private boolean isAnimatorRunning = false;

private int mAnimatorProgress = 0;

private ObjectAnimator mAnimator;

//自定义属性动画

private static final Property BORDER_PROGRESS

= new Property(Integer.class, "borderProgress") {

@Override

public Integer get(SeniorEditText seniorEditText) {

return seniorEditText.getBorderProgress();

}

@Override

public void set(SeniorEditText seniorEditText, Integer value) {

seniorEditText.setBorderProgress(value);

}

};

private Paint mPaint;

public SeniorEditText(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init(context, attrs);

}

public SeniorEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs);

}

private void init(Context context, AttributeSet attrs) {

//抗锯齿和位图滤波

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

//读取xml文件中的配置

if (attrs != null) {

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SeniorEditText);

//获取清除图标资源

clear_res_id = array.getResourceId(R.styleable.SeniorEditText_clearDrawable, R.drawable.ic_content_clear);

//获取可见图标资源

visible_res_id = array.getResourceId(R.styleable.SeniorEditText_visibleDrawable, R.drawable.ic_content_visible);

//获取不可见图标资源

invisible_res_id = array.getResourceId(R.styleable.SeniorEditText_invisibleDrawable, R.drawable.ic_content_invisible);

//可见图标按钮默认宽

visible_res_width = array.getDimensionPixelSize(R.styleable.SeniorEditText_visibleDrawableWidth, dp2px(context,24));

//可见图标按钮默认内边距

visible_res_padding = array.getDimensionPixelSize(R.styleable.SeniorEditText_visibleDrawableSpacing, dp2px(context,5));

//输入框边框样式

edit_border_style = array.getString(R.styleable.SeniorEditText_editFrameStyle);

//输入框边框颜色

edit_border_color = array.getColor(R.styleable.SeniorEditText_editFrameColor, DEFAULT_STYLE_COLOR);

array.recycle();

}

//初始化按钮显示的Bitmap

clear_bitmap = createBitmap(context, clear_res_id, R.drawable.ic_content_clear);

visible_bitmap = createBitmap(context, visible_res_id, R.drawable.ic_content_visible);

invisible_bitmap = createBitmap(context, invisible_res_id, R.drawable.ic_content_invisible);

//如果自定义,则使用自定义的值,否则使用默认值

if (visible_res_padding == 0) {

visible_res_padding = dp2px(context,5);

}

if (visible_res_width == 0) {

visible_res_width = dp2px(context,24);

}

//给文字设置一个padding,避免文字和按钮重叠了

mTextPaddingRight = visible_res_padding * 4 + visible_res_width * 2;

//按钮出现和消失的动画

show_animator = ValueAnimator.ofFloat(1f, 0f).setDuration(ANIMATOR_TIME);

dismiss_animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATOR_TIME);

//是否是密码样式

show_password_image_isShow = getInputType() == (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//设置右内边距, 防止清除按钮和文字重叠

setPadding(getPaddingLeft(), getPaddingTop(), mTextPaddingRight, getPaddingBottom());

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

mPaint.setStyle(Paint.Style.STROKE);

//使用自定义颜色。如未定义,则使用默认颜色

if (edit_border_color != -1) {

mPaint.setColor(edit_border_color);

} else {

mPaint.setColor(DEFAULT_STYLE_COLOR);

}

//控件获取焦点时,加粗边框

if (isFocused()) {

mPaint.setStrokeWidth(DEFAULT_FOCUSED_STROKE_WIDTH);

} else {

mPaint.setStrokeWidth(DEFAULT_UNFOCUSED_STROKE_WIDTH);

}

//绘制边框

drawBorder(canvas);

//绘制清空和明文显示按钮

drawButtons(canvas);

}

private void drawBorder(Canvas canvas) {

int width = getWidth();

int height = getHeight();

switch (edit_border_style) {

//矩形样式

case STYLE_RECT:

setBackground(null);

canvas.drawRect(0, 0, width, height, mPaint);

break;

//圆角矩形样式

case STYLE_ROUND_RECT:

setBackground(null);

float roundRectLineWidth = 0;

if (isFocused()) {

roundRectLineWidth = DEFAULT_FOCUSED_STROKE_WIDTH / 2;

} else {

roundRectLineWidth = DEFAULT_UNFOCUSED_STROKE_WIDTH / 2;

}

mPaint.setStrokeWidth(roundRectLineWidth);

if (Build.VERSION.SDK_INT >= 21) {

canvas.drawRoundRect(

roundRectLineWidth / 2, roundRectLineWidth / 2, width - roundRectLineWidth / 2, height - roundRectLineWidth / 2,

DEFAULT_ROUND_RADIUS, DEFAULT_ROUND_RADIUS,

mPaint);

} else {

canvas.drawRoundRect(

new RectF(roundRectLineWidth / 2, roundRectLineWidth / 2, width - roundRectLineWidth / 2, height - roundRectLineWidth / 2),

DEFAULT_ROUND_RADIUS, DEFAULT_ROUND_RADIUS,

mPaint);

}

break;

//半矩形样式

case STYLE_HALF_RECT:

setBackground(null);

canvas.drawLine(0, height, width, height, mPaint);

canvas.drawLine(0, height / 2, 0, height, mPaint);

canvas.drawLine(width, height / 2, width, height, mPaint);

break;

//动画特效样式

case STYLE_ANIMATOR:

setBackground(null);

if (isAnimatorRunning) {

canvas.drawLine(width / 2 - mAnimatorProgress, height, width / 2 + mAnimatorProgress, height, mPaint);

if (mAnimatorProgress == width / 2) {

isAnimatorRunning = false;

}

} else {

canvas.drawLine(0, height, width, height, mPaint);

}

break;

default:

break;

}

}

private void drawButtons(Canvas canvas) {

if (clear_image_isShow) {

//播放按钮出现的动画

if (dismiss_animator.isRunning()) {

float scale = (float) dismiss_animator.getAnimatedValue();

drawClearButton(scale, canvas);

if (show_password_image_isShow) {

drawVisibleButton(scale, canvas, dismiss_password_image_isShow);

}

invalidate();

//绘制静态的按钮

} else {

drawClearButton(1, canvas);

if (show_password_image_isShow) {

drawVisibleButton(1, canvas, dismiss_password_image_isShow);

}

}

} else {

//播放按钮消失的动画

if (show_animator.isRunning()) {

float scale = (float) show_animator.getAnimatedValue();

drawClearButton(scale, canvas);

if (show_password_image_isShow) {

drawVisibleButton(scale, canvas, dismiss_password_image_isShow);

}

invalidate();

}

}

}

private void drawClearButton(float scale, Canvas canvas) {

int right = (int) (getWidth() + getScrollX() - visible_res_padding - visible_res_width * (1f - scale) / 2f);

int left = (int) (getWidth() + getScrollX() - visible_res_padding - visible_res_width * (scale + (1f - scale) / 2f));

int top = (int) ((getHeight() - visible_res_width * scale) / 2);

int bottom = (int) (top + visible_res_width * scale);

Rect rect = new Rect(left, top, right, bottom);

canvas.drawBitmap(clear_bitmap, null, rect, mPaint);

}

private void drawVisibleButton(float scale, Canvas canvas, boolean isVisible) {

int right = (int) (getWidth() + getScrollX() - visible_res_padding * 3 - visible_res_width - visible_res_width * (1f - scale) / 2f);

int left = (int) (getWidth() + getScrollX() - visible_res_padding * 3 - visible_res_width - visible_res_width * (scale + (1f - scale) / 2f));

int top = (int) ((getHeight() - visible_res_width * scale) / 2);

int bottom = (int) (top + visible_res_width * scale);

Rect rect = new Rect(left, top, right, bottom);

if (isVisible) {

canvas.drawBitmap(visible_bitmap, null, rect, mPaint);

} else {

canvas.drawBitmap(invisible_bitmap, null, rect, mPaint);

}

}

// 清除按钮出现时的动画效果

private void startVisibleAnimator() {

endAllAnimator();

dismiss_animator.start();

invalidate();

}

// 清除按钮消失时的动画效果

private void startGoneAnimator() {

endAllAnimator();

show_animator.start();

invalidate();

}

// 结束所有动画

private void endAllAnimator() {

show_animator.end();

dismiss_animator.end();

}

@Override

protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {

super.onFocusChanged(focused, direction, previouslyFocusedRect);

//播放按钮出现和消失动画

if (focused && getText().length() > 0) {

if (!clear_image_isShow) {

clear_image_isShow = true;

startVisibleAnimator();

}

} else {

if (clear_image_isShow) {

clear_image_isShow = false;

startGoneAnimator();

}

}

//实现动画特效样式

if (focused && edit_border_style.equals(STYLE_ANIMATOR)) {

isAnimatorRunning = true;

mAnimator = ObjectAnimator.ofInt(this, BORDER_PROGRESS, 0, getWidth() / 2);

mAnimator.setDuration(ANIMATOR_TIME);

mAnimator.start();

}

}

protected void setBorderProgress(int borderProgress) {

mAnimatorProgress = borderProgress;

postInvalidate();

}

protected int getBorderProgress() {

return mAnimatorProgress;

}

@Override

protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {

super.onTextChanged(text, start, lengthBefore, lengthAfter);

if (text.length() > 0 && isFocused()) {

if (!clear_image_isShow) {

clear_image_isShow = true;

startVisibleAnimator();

}

} else {

if (clear_image_isShow) {

clear_image_isShow = false;

startGoneAnimator();

}

}

}

@Override

public boolean onTouchEvent(MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_UP) {

boolean clearTouched =

(getWidth() - visible_res_padding - visible_res_width < event.getX())

&& (event.getX() < getWidth() - visible_res_padding)

&& isFocused();

boolean visibleTouched =

(getWidth() - visible_res_padding * 3 - visible_res_width * 2 < event.getX())

&& (event.getX() < getWidth() - visible_res_padding * 3 - visible_res_width)

&& show_password_image_isShow && isFocused();

if (clearTouched) {

setError(null);

setText("");

return true;

} else if (visibleTouched) {

if (dismiss_password_image_isShow) {

dismiss_password_image_isShow = false;

setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT);

setSelection(getText().length());

invalidate();

} else {

dismiss_password_image_isShow = true;

setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);

setSelection(getText().length());

invalidate();

}

return true;

}

}

return super.onTouchEvent(event);

}

/**

* 开始晃动的入口

*/

public void startShakeAnimation() {

if (getAnimation() == null) {

setAnimation(shakeAnimation(4));

}

startAnimation(getAnimation());

}

/**

* 晃动动画

*

* @param counts 0.5秒钟晃动多少下

* @return

*/

private Animation shakeAnimation(int counts) {

Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);

translateAnimation.setInterpolator(new CycleInterpolator(counts));

translateAnimation.setDuration(500);

return translateAnimation;

}

private Bitmap createBitmap(Context context, int resId, int defResId) {

if (resId != 0) {

return BitmapFactory.decodeResource(context.getResources(), resId);

} else {

return BitmapFactory.decodeResource(context.getResources(), defResId);

}

}

public int dp2px(Context context, float dpValue){

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,context.getResources().getDisplayMetrics());

}

}

XML

android:inputType="textPassword"

app:clearDrawable="@drawable/ic_content_clear"

app:visibleDrawable="@drawable/ic_content_visible"

app:invisibleDrawable="@drawable/ic_content_invisible"

app:editFrameStyle="roundRect"

app:editFrameColor="#5D2BC5"

android:layout_marginTop="30dp"

android:layout_marginStart="20dp"

android:layout_marginEnd="20dp"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

资源图标

ic_content_clear.png

ic_content_invisible.png

ic_content_visible.png

android中edittext设置密码格式,Android 自定义EditText(带清理、密码可见、不可见)...相关推荐

  1. android 视频转字节,如何将视频文件(.mp4)格式转换为android中的二进制格式?...

    我想在网络服务器上传视频.我得到了我想要以二进制格式传递文件的服务,我该怎么做?如何将视频文件(.mp4)格式转换为android中的二进制格式? 我试图通过base64将视频文件转换为二进制格式.. ...

  2. Android解析xml的方法,Android中解析XML格式数据的方法

    XML介绍:Extensible Markup Language,即可扩展标记语言 一.概述 Android中解析XML格式数据大致有三种方法: SAX DOM PULL 二.详解 2.1 SAX S ...

  3. android如何实现每周自定义闹钟,Android中使用alarmManager+PendingIntent实现自定义闹钟...

    Android中使用alarmManager+PendingIntent实现自定义闹钟 发布时间:2020-11-24 15:36:41 来源:亿速云 阅读:154 作者:Leah 今天就跟大家聊聊有 ...

  4. android edittext hint文字居中,自定义EditText设置图片文字居中

    JAVA 自定义类继承EditText or AppCompatEditText import android.content.Context; import android.graphics.Pai ...

  5. android drawable 比例,Android中的Drawable基础与自定义Drawable

    转载请注明链接:http://blog..net/feather_wch/article/details/79124608 本文要点: 1. 介绍Android中Drawable的相关知识点,并且介绍 ...

  6. Android中URI的格式

    在Android中,为了使用数据集中管理模式,使用了ContentProvider来进行数据管理,在使用ContentProvider进行 数据交互时就需要用到URI.为了让客户端程序能够使用你的数据 ...

  7. Android中的Drawable基础与自定义Drawable

    转载请注明链接:http://blog.csdn.net/feather_wch/article/details/79124608 本文要点: 1. 介绍Android中Drawable的相关知识点, ...

  8. java 自定义函数的调用_Java/Android中的函数调用回调函数自定义回调函数

    在做Android自定义控件时遇到要自定义回调函数的问题,想想自己还暂时没有那么精深的技术,赶紧返过头回来再重新研究Java中回调函数的问题.然而不幸的是,网上太多杂乱的帖子和博客都是转来转去,而且都 ...

  9. 自定义注解在拦截器中为空_如何在Android中为特定联系人设置自定义铃声

    自定义注解在拦截器中为空 Everyone likes to know who's calling before they actually pick up the phone, and the ea ...

最新文章

  1. 哈啰程序员吐槽:试用期带5个人创造了部门历史最高成绩,结果却被辞退
  2. 人脸检测--SSH: Single Stage Headless Face Detector
  3. 自学python可以做什么兼职-一行生财:毕业100天,通过副业赚(挣)到我的第一个10w...
  4. python语言的变量特点随时_【Python】Python语言特点
  5. 学而思编程python软件怎么样_学而思编程社区缺点详细分析
  6. linux运维搭建官网,Linux运维学习之LAMP搭建个人博客网站
  7. 如何将Eclipse设置为中文简体
  8. linux系统下,我也用虚拟机——linux虚拟机随笔
  9. 【图形学概览】几何折叠 Geometric Folding
  10. Vijos——T 1092 全排列
  11. 电商中,订单号的生成方法
  12. 计算机与3d打印导板,计算机导航系统、3D打印截骨导板与传统器械对全膝关节置换术手术时间和下肢力线恢复的影响...
  13. 马尔可夫毯/马尔科夫链/因果图/贝叶斯网络
  14. 基于共识算法和区块链模拟实现超级账本
  15. mysqldump加速导入参数说明
  16. html 单元格被撑开_CSS教程:表格不被撑开的解决办法—css教程
  17. 听说你想用开发者工具调试我的网站?挺可以的啊。25
  18. 200页!这可能是最牛逼的Python自学手册啦!
  19. 这几种[儿童益智玩具] 永远不过时!
  20. 在图片上加播放按钮示例代码

热门文章

  1. 学习css3的弹性盒模型
  2. 如何定一个合适的目标
  3. hibernate select 读取结果集的两种办法
  4. CPU步进号(版本号)
  5. 财会小白的办公室自救指南
  6. Dubbo源码解析 --- DIRECTORY和ROUTER
  7. mongodb启动不了:child process failed, exited with err
  8. kali linux 为firefox添加图标
  9. 2013年F5应用交付高峰论坛北京站落幕
  10. 不可小瞧的GetHashCode函数