开发者

Android: extending widgets and canvas bounds - extending Button

开发者 https://www.devze.com 2023-04-01 01:43 出处:网络
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.

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 );
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消