有很多人希望能在一个EditText中嵌入一个Button,用作搜索、清除等作用。但是EditText并不是一个ViewGroup,所以,要实现在EditText中嵌入一个Button,并不是一个非常简单的事情,当然,也不是太复杂。 :)
下面我给一个最简单的方案,当然,这个方案可以继续完善以满足你的需求。
这里我实现的Button是放在EditText的右部。首先声明了一个类ButtonEditText继承自EditText,然后定义了一个Button,以及控制这个Button的高度、宽度的padding。高度的padding是指Button和EditText上下边框的距离,而宽度的padding是指Button和EditText右边框的距离。
public class ButtonEditText extends EditText {
private Button mButton;
private int mButtonHeightPadding = 10;
private int mButtonWeightPadding = 10;
}
然后根据父类定义构造函数。init()函数是定义来初始化Button的,这里初始化Button比较简单,只设置了一个Text和ClickListener,如果需要更加复杂的初始化工作,可能需要用到自定义的attribute,详见这篇文章http://sxote.blog.51cto.com/885634/1112857。
public ButtonEditText(Context context) {
super(context);
init();
}
public ButtonEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ButtonEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mButton = new Button(getContext());
mButton.setText("ME");
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "Clicked me!", Toast.LENGTH_SHORT).show();
}
});
}
为了实现Button的点击效果,必须要把Touch的事件传递给Button,所以必须要重载dispatchTouchEvent()函数,如下:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getY() > mButtonHeightPadding && event.getY() < getHeight() - mButtonHeightPadding &&
event.getX() > getWidth() - mButtonWeightPadding - mButton.getMeasuredWidth() &&
event.getX() < getWidth() - mButtonWeightPadding) {
return mButton.dispatchTouchEvent(event);
}
return super.dispatchTouchEvent(event);
}
上面的对event.getY() 和event.getX()的判断就是为了定位Touch事件发生在Button上,如果发生在Button上,就给它传递Touch事件。否则就用EditText的dispatchTouchEvent()函数。如果你需要对Button做一些高级的效果,这里可能还需要判断Button是否需要ACTION_OUTSIDE/ACTION_CANCEL消息。
下面就需要对Button的显示进行处理了。显示首先是measure()、layout(),然后是draw(),缺一不可。重载如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mButton.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(getMeasuredHeight() - mButtonHeightPadding * 2, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mButton.layout(0, 0, mButton.getMeasuredWidth(), mButton.getMeasuredHeight());
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
canvas.translate(getMeasuredWidth() - (mButton.getMeasuredWidth() + mButtonWeightPadding), mButtonHeightPadding);
mButton.draw(canvas);
canvas.restore();
}
最后的效果如下图所示:
附完整源文件:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class ButtonEditText extends EditText {
private Button mButton;
private int mButtonHeightPadding = 10;
private int mButtonWeightPadding = 10;
public ButtonEditText(Context context) {
super(context);
init();
}
public ButtonEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ButtonEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mButton = new Button(getContext());
mButton.setText("ME");
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "Clicked me!", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getY() > mButtonHeightPadding && event.getY() < getHeight() - mButtonHeightPadding &&
event.getX() > getWidth() - mButtonWeightPadding - mButton.getMeasuredWidth() &&
event.getX() < getWidth() - mButtonWeightPadding) {
return mButton.dispatchTouchEvent(event);
}
return super.dispatchTouchEvent(event);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mButton.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(getMeasuredHeight() - mButtonHeightPadding * 2, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mButton.layout(0, 0, mButton.getMeasuredWidth(), mButton.getMeasuredHeight());
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
canvas.translate(getMeasuredWidth() - (mButton.getMeasuredWidth() + mButtonWeightPadding), mButtonHeightPadding);
mButton.draw(canvas);
canvas.restore();
}
}