[Android]实现带显示密码按钮的EditText(无内存泄露)

原理:

通过自定义View绘制显示密码按钮,当点击密码按钮的时候调用setInputType来更改属性。

解决方案:

就直接上代码了

package com.finals.view;

import com.example.test.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;

public class PassEditText extends EditText {

	int mThumbWidth;
	int mThumbHeight;

	int offsetX;
	int offsetY;

	boolean isShowPass = false;

	Drawable mThumbDrawable;

	Bitmap mThumbDefault;

	public PassEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		InitDrawable(context, attrs);
	}

	public PassEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		InitDrawable(context, attrs);
	}

	private void InitDrawable(Context context, AttributeSet attrs) {
		float density = context.getResources().getDisplayMetrics().density;

		TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.windows);
		mThumbDrawable = mTypedArray.getDrawable(R.styleable.windows_thumb);
		mThumbWidth = (int) mTypedArray.getDimension(R.styleable.windows_thumb_width, 20 * density);
		mThumbHeight = (int) mTypedArray.getDimension(R.styleable.windows_thumb_height, 20 * density);

		if (mThumbDrawable == null) {
			mThumbDefault = getThumbDefault();
		} else {
			mThumbDrawable.setBounds(0, 0, (int) mThumbWidth, (int) mThumbHeight);
		}
		mTypedArray.recycle();
		if (getInputType() != (EditorInfo.TYPE_TEXT_VARIATION_PASSWORD | EditorInfo.TYPE_CLASS_TEXT)) {
			isShowPass = true;
		}
	}

	@Override
	public int getCompoundPaddingRight() {
		return super.getCompoundPaddingRight() + mThumbWidth;
	}

	@Override
	public void draw(Canvas canvas) {
		super.draw(canvas);
		drawThumb(canvas);
	}

	void drawThumb(Canvas canvas) {
		offsetX = getWidth() - mThumbWidth - getPaddingRight();
		offsetY = (getHeight() - mThumbHeight) / 2;
		if (mThumbDrawable != null) {
			canvas.save();
			canvas.translate(getScrollX() + offsetX, getScrollY() + offsetY);
			mThumbDrawable.draw(canvas);
			canvas.restore();
		} else if (mThumbDefault != null) {
			canvas.drawBitmap(mThumbDefault, getScrollX() + offsetX, getScrollY() + offsetY, null);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			checkThumb(event);
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
	}

	void checkThumb(MotionEvent event) {
		float x = event.getX();
		float y = event.getY();
		if (x > offsetX && x < offsetX + mThumbWidth && y > offsetY && y < offsetY + mThumbHeight) {
			if (!isShowPass) {
				isShowPass = true;
				this.setInputType(EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
			} else {
				isShowPass = false;
				this.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD | EditorInfo.TYPE_CLASS_TEXT);
			}
		}
	}

	@Override
	protected void onAttachedToWindow() {
		if (mThumbDrawable == null) {
			mThumbDefault = getThumbDefault();
		}
		super.onAttachedToWindow();
	}

	@Override
	protected void onDetachedFromWindow() {
		if (mThumbDefault != null) {
			mThumbDefault.recycle();
			mThumbDefault = null;
		}
		super.onDetachedFromWindow();
	}

	/**
	 * 创建默认图片
	 *
	 * @return
	 */
	private Bitmap getThumbDefault() {
		float density = getContext().getResources().getDisplayMetrics().density;
		int stokenWidth = (int) (3 * density);

		Paint mPaint = new Paint();
		mPaint.setColor(Color.BLACK);
		mPaint.setStyle(Style.FILL);
		mPaint.setAntiAlias(true);
		Bitmap mBitmap = Bitmap.createBitmap(mThumbWidth, mThumbHeight, Config.ARGB_4444);
		Canvas mCanvas = new Canvas(mBitmap);
		mCanvas.drawCircle(mThumbWidth / 2, mThumbHeight / 2, mThumbWidth * 0.30F - stokenWidth, mPaint);

		mPaint.setStyle(Style.STROKE);

		mPaint.setStrokeWidth(stokenWidth);

		RectF oval = new RectF(stokenWidth, stokenWidth, mThumbWidth - stokenWidth, mThumbHeight - stokenWidth);
		mCanvas.drawArc(oval, -175, 170, false, mPaint);
		return mBitmap;
	}

	public boolean isShowPassword() {
		return isShowPass;
	}

}
时间: 2024-11-06 06:29:36

[Android]实现带显示密码按钮的EditText(无内存泄露)的相关文章

基于Chromium的浏览器已上线通用“显示密码”按钮

基于Chromium的Edge在日前发布的Canary通道版本中,对用户界面进行了优化调整从而让InPrivate窗口变得更加简洁.在今天获得的版本更新中,微软继续带来了隐私相关的新内容--实现通用的“显示密码”按钮. 这项功能是众多“受控功能部署”的功能之一,微软解释道: 为< input type="password"/>部署显示密码按钮.这个新添加的按钮是和< input type="search"/>清除/取消按钮相同的模式,在con

Android 自定义带回调的Dialog 及EditText相关

  import android.app.Activity; import android.content.Context; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View

Android中使用Handler(消息机制)造成内存泄露的分析和解决

问题描述: Handler 内部类持有 外部类Activity的引用,如果Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露. 解决方案: 1.onDestroy时清除消息. mHandler.removeCallbacksAndMessages(null); // 参数为null时会清除所有消息. 2.声明Handler为static并持有Activity的弱引用. public class MainActivity ext

Android 内存泄露总结(附内存检测工具)

https://segmentfault.com/a/1190000006852540 主要是分三块: 静态储存区:编译时就分配好,在程序整个运行期间都存在.它主要存放静态数据和常量. 栈区:当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存. 堆区:通常存放 new 出来的对象.由 Java 垃圾回收器回收. 栈与堆的区别 栈内存用来存放局部变量和函数参数等.它是先进后出的队列,进出一一对应,不产生碎片,运行效率稳定高.当超过变量的作用域后,该变量也就无效了,分配给它

Android 内存泄露测试数据处理--procrank,setprop,getprop(转)

1.Android内存测试常用的几个概念. VSS--virtual set size 虚拟耗用内存(包含共享库占用的内存)RSS--Resident set size实际使用的物理内存(包含共享库占用的内存)PSS--Proportional set size 实际使用的物理内存(比例分配共享库占用的内存)USS--Unique Set size:进程独自占用的物理内存(不包含共享库占用的内存)一般来说内存占用大小如下规律:VSS>=RSS>=Pss>=USS 2.Android pr

[Android Memory] App调试内存泄露之Context篇(上)

转载自:http://www.cnblogs.com/qianxudetianxia/p/3645106.html Context作为最基本的上下文,承载着Activity,Service等最基本组件.当有对象引用到Activity,并不能被回收释放,必将造成大范围的对象无法被回收释放,进而造成内存泄漏. 下面针对一些常用场景逐一分析. 1. CallBack对象的引用 先看一段代码: @Override protectedvoid onCreate(Bundle state){ super.o

android 实现带清除效果的EditText(附带抖动效果)

Android一直没有提供类似于ios中自带清除效果的输入框(ios只要只要添加属性即可实现),所以在Android当中 想要实现此效果就需要使用自定义控件的方式实现. 思路:可以使用一个Linearlayout里面横向布局一个EditText和一个删除的图片,监听输入框的焦点和文字变化,设置图片的显隐和点击清除事件.但是这么做些弊端,首先增加了UI布局的层级结构不利于UI结构的优化而且可能会出现文字过长遮挡住图片的情况.所以采用自定义控件继承于EditText,使用getCompoundDra

Android中CleanEditText自动带X号输入框的EditText

图标在这里.你懂得 实现的效果如下: 今天做项目遇到的问题.记录下.自动带删除按钮的EditText. public class CleanEditText extends EditText implements OnFocusChangeListener, TextWatcher { /** * 删除按钮的引用 */ private Drawable mClearDrawable; public CleanEditText(Context context) { this(context, nu

Android 基础一 TextView,Style样式,Activity 传值,选择CheckBox 显示密码

1.修改TextView字体 mTextView = (TextView) findViewById(R.id.textview1); mTextView.setText("I am here"); Resources resources = getBaseContext().getResources(); Drawable myDrawable = resources.getDrawable(R.drawable.Drawable1); mTextView.setBackground