android中如何自定义attribute
有很多人希望能在一个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(); } }
更多相关文章
- Android 自定义View 解耦框架
- Android 自定义组件02
- android中颜色的定义
- Android一些实用的函数
- 将retrofit2和rxjava的初始化配置到application
- Android调用系统自定义设置界面
- Android 自定义布局的Toast
- Android 之 自定义适配器
- Android 自定义view的简单应用(2) 毛玻璃效果