现在的位置: 首页 > 移动开发 > 正文

android中如何自定义attribute

2019年07月29日 移动开发 ⁄ 共 4432字 ⁄ 字号 评论关闭

有很多人希望能在一个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(); 
    } 
} 

抱歉!评论已关闭.