Search code examples
androidxmllayoutnine-patch

9patch image as CheckBox in android


I'm very new to 9patches and I still tries to figure out how it works. I try to make CheckBox with 9 patches but they not scale properly. So my XML file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/checkbox_cases_checked" android:state_checked="true" />
    <item android:drawable="@drawable/checkbox_cases_default" android:state_checked="false"  />
    <item android:drawable="@drawable/checkbox_cases_default" />
</selector>

in draw9patch.bat 9path scales fine to me: Scaling 9patch in draw9patch.bat but in prewiev it dosn't scale:

Scaling in AS preview

In layout code for CheckBox looks like this:

<android.support.v7.widget.AppCompatCheckBox
                android:id="@+id/stepCheckBox1"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:button="@drawable/checkbox_cases" />

I really don't know why this image dont scale up for 48dp to 48dp. Some help would be appreciated :) Thanks!


Solution

  • Digging into this, it looks like CheckBox itself doesn't support scaling of 9-patch Drawables. The onDraw() method in CompoundDrawable (from which CheckBox is derived), appears to set the drawable bounds from the intrinsic drawable size (as opposed to the setting the bounds from the container size) - which means it doesn't scale.

    The background (which is drawn by View itself) does scale correctly, so you could just set the selector drawable on that.

    If however (like me) you wanted a separate background and 'check' drawable, (and you're comfortable with custom views) then you can just subclass ImageView and make that Checkable instead :

    public class StyledCheckBox extends ImageView implements Checkable, View.OnClickListener {
        private static final int[] CHECKED_STATE = { android.R.attr.state_checked };
    
        private boolean mChecked;
    
        public StyledCheckBox(Context context) {
            this(context, null, 0);
        }
    
        public StyledCheckBox(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public StyledCheckBox(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs);
    
            setFocusable(true);
            setOnClickListener(this);
    
            // Other constructor stuff...
        }
    
        @Override
        public void onClick(View v) {
            toggle();
        }
    
        @Override
        public boolean isChecked() {
            return mChecked;
        }
    
        @Override
        public void setChecked(boolean checked) {
            if (mChecked == checked) return;
            mChecked = checked;
            refreshDrawableState();
        }
    
        @Override
        public void toggle() {
            setChecked(!mChecked);
        }
    
        @Override
        public int[] onCreateDrawableState(int extraSpace) {
            if (isChecked()){
                int[] state = super.onCreateDrawableState(extraSpace + 1);
                mergeDrawableStates(state, CHECKED_STATE);
                return state;
            } else {
                return super.onCreateDrawableState(extraSpace);
            }
        }
    }