Android: extending widgets and canvas bounds - extending Button
All i wanted was to create a button that in some cases will contain a 'v' image to mark that it's active. not really a check box since not every time you press the button it changes it's state.
But the idea is this. I need a plain button and i have another small image of 'v' that if i use a toggle() method on that button the button will get extended enough so the 'v' image can squeeze nicely to it's upper right corner.
this is my code:
public class ButtonWithV extends Button {
private Drawable mVImageDrawable;
private int mImageWidth;
private boolean mIsMarked;
public ButtonWithV(Context context) {
this(context, null);
}
public ButtonWithV(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.ButtonWithVStyle);
}
public ButtonWithV(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mImageWidth = 0;
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ButtonWithV, defStyle, 0);
Drawable d = a.getDrawable(R.styleable.ButtonWithV_button_v_drawable);
if( d != null){
setVImageDrawable(d);
}
// setPadding(getPaddingLeft(), getPaddingTop(),
// getPaddingRight(), getPaddingBottom());
mIsMarked = false;
}
public void setMarked(boolean marked){
if( marked != mIsMarked){
mIsMarked = marked;
requestLayout();
// invalidate();
}
}
private void setVImageDrawable(Drawable d) {
mVImageDrawable = d;
mImageWidth = mVImageDrawable.getIntrinsicWidth();
}
@Override
protected void onDraw(Canvas canvas) {
Rect temp = canvas.getClipBounds();
System.out.println(String.format("top: %d, bottom: %d, left: %d, right: %d",
temp.top, temp.bottom, temp.left, temp.right));
super.onDraw(canvas);
System.out.println(String.format("top: %d, bottom: %d, left: %d, right: %d",
temp.top, temp.bottom, temp.left, temp.right));
if( mVImageDrawable != null && mIsMarked){
Rect bounds = canvas.getClipBounds();
int right = bounds.right - 5;
int left = right - mImageWidth;
int top = bounds.top + 2;
int bottom = top + mVImageDrawable.getIntrinsicHeight();
mVImageDrawable.setBounds(left, top, right, bottom);
mVImageDrawable.draw(canvas);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if( mIsMarked ){
setMeasuredDimension(getMeasuredWidth() + mImageWidth, getMeasuredHeight());
}
}
public void toggle(){
setMarked(! mIsMarked );
}
}
Please note the -5 and +2 (they cannot remain as such i just wanted to see exact numbers). What I find problematic here, and will probably be problematic, is in all widgets I cannot use the widget's getRight(), getLeft() etc...
开发者_Go百科Since they give me the REAL widget location on the canvase, however (in onDraw
) when I get the canvas it's clipped and translated to (0,0).
If I get it correctly and I want to know the widget's rightest corner I need to get the clip rightest corner or the measured width. same goes for the height.
Another problem is I have no idea how the background is drown but I do know that since I have to remove 5 pixels from the right of the widget to get to it's exact right position it means inner margins or padding.
It's not regular paddings, I checked. so what can it be ? how can I get, always, including when user set paddings and margins the upper right relative coordinates ? I need to draw there.
eventually i used padding to solve the issue, i just add more padding the width of the needed button to the right so i can draw the overlay image. here's the fixed code snapshot:
public void setMarked(boolean marked){
if( marked != mIsMarked){
mIsMarked = marked;
requestLayout();
}
}
private void setVImageDrawable(Drawable d) {
mVImageDrawable = d;
mImageWidth = mVImageDrawable.getIntrinsicWidth();
}
@Override
public int getCompoundPaddingRight() {
int orig = super.getCompoundPaddingRight();
int res = orig;
if( mIsMarked ){
res += mImageWidth;
}
return res;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if( mVImageDrawable != null && mIsMarked){
Rect bounds = canvas.getClipBounds();
int right = bounds.right;
int left = right - mImageWidth;
int top = bounds.top;
int bottom = top + mVImageDrawable.getIntrinsicHeight();
mVImageDrawable.setBounds(left, top, right, bottom);
mVImageDrawable.draw(canvas);
}
}
public void toggle(){
setMarked(! mIsMarked );
}
精彩评论