android editview自定义带文本,Android自定义View------带删除功能的EditText

以前在为EditText添加左侧图标,以及右侧一个删除按钮时,经常是使用FrameLayout,当这样代码复用差,维护也麻烦。最好的方法是重写EditText实现该功能。现在看看效果图,后面再讲解实现方式。

d4df2fc0c8f4726d69e869ab02f67593.png

重写之后的组件有如下功能,只有当EditText内容不为空,而且获得焦点,才会出现删除按钮,点击删除按钮则清空内容。代码如下:

public class CleanableEditText extends EditText {

//回调函数

private TextWatcherCallBack mCallback;

//右侧删除图标

private Drawable mDrawable;

private Context mContext;

public void setCallBack(TextWatcherCallBack mCallback) {

this.mCallback = mCallback;

}

public CleanableEditText(Context context) {

super(context);

this.mContext = context;

init();

}

public CleanableEditText(Context context, AttributeSet attrs) {

super(context, attrs);

this.mContext = context;

init();

}

public CleanableEditText(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

this.mContext = context;

init();

}

public void init() {

mDrawable = mContext.getResources().getDrawable(R.drawable.ic_clear);

mCallback = null;

//重写了TextWatcher,在具体实现时就不用每个方法都实现,减少代码量

TextWatcher textWatcher = new TextWatcherAdapter() {

@Override

public void afterTextChanged(Editable s) {

//更新状态,检查是否显示删除按钮

updateCleanable(length(), true);

//如果有在activity中设置回调,则此处可以触发

if(mCallback != null)

mCallback.handleMoreTextChanged();

}

};

this.addTextChangedListener(textWatcher);

this.setOnFocusChangeListener(new OnFocusChangeListener() {

@Override

public void onFocusChange(View v, boolean hasFocus) {

//更新状态,检查是否显示删除按钮

updateCleanable(length(), hasFocus);

}

});

}

//当内容不为空,而且获得焦点,才显示右侧删除按钮

public void updateCleanable(int length, boolean hasFocus){

if(length() > 0 && hasFocus)

setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawable, null);

else

setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

final int DRAWABLE_RIGHT = 2;

//可以获得上下左右四个drawable,右侧排第二。图标没有设置则为空。

Drawable rightIcon = getCompoundDrawables()[DRAWABLE_RIGHT];

if (rightIcon != null && event.getAction() == MotionEvent.ACTION_UP) {

//检查点击的位置是否是右侧的删除图标

//注意,使用getRwwX()是获取相对屏幕的位置,getX()可能获取相对父组件的位置

int leftEdgeOfRightDrawable = getRight() - getPaddingRight()

- rightIcon.getBounds().width();

if (event.getRawX() >= leftEdgeOfRightDrawable) {

setText("");

}

}

return super.onTouchEvent(event);

}

@Override

protected void finalize() throws Throwable {

mDrawable = null;

super.finalize();

}

}

实现的关键有两点,其中一点是得知道有API可以为EditText设置上下左右的图标,所以,就可以避免使用FrameLayout那种笨拙的方法(此处右侧图标在组件的代码中自动加入了,左侧图标则需要在XML代码中声明)。需要注意的另一点是得知道如何计算点击事件的位置,

实现过程遇到的一个小问题,在onTouchEvent()方法中,如果消耗事件(依据情况返回true或者false),则会出现一个问题,可以点击EditText,如果设置日志输出,可以发现action_down,action_move,action_up都输出了,代表点击事件正常,但是依然无法获得焦点。所以不难猜测EditText获得焦点可能和点击事件有关。如果强制调用requestFocus()方法,则可以“解决”这个问题,但是存在不稳定现象,有时会出bug,其中原因还没细究。于是,此处我不处理点击事件,直接返回super.onTouchEvent(event)

编码上用了几个小技巧

1,addTextChangedListener时发现经常需要实现三个方法,但是我们又只需重写一个,显得代码有点冗余,解决方式是增加一个adapter。

2,此处已经addTextChangedListener了,那么如果我在activity中也需要监听呢,如果直接监听,则会覆盖CleanableEditText中的监听。为了解决这个方法,我使用了一个回调接口,使用户在addTextChangedListener中有选择的做更多事情。实现方式如下

回调接口的代码如下:

public interface TextWatcherCallBack {

public void handleMoreTextChanged();

}

activity需要实现TextWatcherCallBack,并且为CleanableEditText设置callback(如以下代码最后两句)

public class LoginActivity extends BaseActivity implements TextWatcherCallBack {

private ClearableAutoCompleteTextView accountView;

private CleanableEditText passwordText;

private Button login;

@Override

protected void onCreate(Bundle bundle) {

super.onCreate(bundle);

setContentView(R.layout.activity_login);

accountView = (ClearableAutoCompleteTextView) findViewById(R.id.et_account);

passwordText = (CleanableEditText) findViewById(R.id.et_password);

login = (Button) findViewById(R.id.bt_login);

accountView.setCallBack(this);

passwordText.setCallBack(this);

//,,,,,,,

}

}

该自定义组件的用法写到这,现在已用于我的一个XMPP即时通讯工具,托管在Github上。

master分支是刚入门android写的代码,很差很渣,我自己都看不下去,不过唯一的价值是让我现在能参考smack开发包的API使用,当时也给我写android入门练手了。develop分支是痛下决心重新写的,今晚刚撸了登陆界面。接下来业余时间主要就维护这个项目,尽量多用上android各种知识。并写博客记录这些知识。欢迎fork欢迎提issue。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值