Sound Conception
Sound Conception

Reputation: 5411

Get programmatically created button to correctly implement padding from 9Patch

I am using the 9Patch drawable shown below as the background for buttons.
When the buttons are drawn they do not appear to be using the padding as defined in the 9Patch by default.

test_background.9.png

I have searched and found others have had the same problem. It is suggested that the issue is that the default button style overrides the padding defined in the 9Patch. One user solved the issue by setting android:padding="@null" in their XML.

I however, need to achieve the same programmatically instead of in XML.
In my test app below I have tried numerous things to get the buttons to reflect the padding as defined in the 9Patch:

  1. Setting all margins to 0 for the LayoutParams
  2. Manually setting all padding for the button to 0. (Ref. Button A)
  3. Setting the minimum height of the button View to a value smaller than the height of the text. (Ref. Button B)
  4. Setting the minimum height of the button's TextView to a value smaller than the height of the text. (Ref. Button C)
  5. Setting both the minimum height of the button View & the button's TextView to a value smaller than the height of the text (in other words, combining tests 3 & 4). (Ref. Button D)
  6. Manually transferring the padding from the 9Patch as per dandc87's suggestion. (Ref. Button E)
  7. Using the 9Patch with an ImageButton instead of a Button. (Ref. Button F)

As you can see below, only Button D (Test 5) and ImageButton F (Test 7) implement the padding as defined in the 9Patch. Why is this so?

Setting both the View and TextView minimum height to a small value seems like a messy hack.
The core of my question is: What is the correct way to get a programmatically created button to correctly reflect the padding defined in a 9Patch.
enter image description here
Below I've tabulated some of the info after inspecting each test button in Hierarchy View.

// Measurement info from Hierarchy View
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Button            A   B   C   D   E   F
// ------------------------------------------
// mMeasuredHeight   64  64  64  44  64  54
// mMeasuredWidth    85  85  85  85  85  57
// mMinHeight        64  1   64  1   64  0
// mMinWidth         85  85  85  85  85  0


// Padding info from Hierarchy View 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Button                A  B            C            D            E            F
// ------------------------------------------------------------------------------------------
// mPaddingBottom        4  4            4            4            4            4
// mPaddingLeft          7  7            7            7            7            7
// mPaddingRight         7  7            7            7            7            7
// mPaddingTop           7  7            7            7            7            7
// mUserPaddingBottom    4  4            4            4            4            4
// mUserPaddingEnd       0  -2147483648  -2147483648  -2147483648  -2147483648  -2147483648
// mUserPaddingLeft      7  7            7            7            7            7
// mUserPaddingRight     7  7            7            7            7            7
// mUserPaddingStart     0  -2147483648  -2147483648  -2147483648  -2147483648  -2147483648

NOTE:
In Test 2 I have tried calling setPaddingRelative() which the android Reference documentation indicates is equivalent to the XML attribute android:padding (I tried setting the padding to 0 and also to -1).

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.main_layout);
        LinearLayout testLayout = new LinearLayout(this);
        mainLayout.addView(testLayout);

        // Test (1): Setting all margins to 0 for the LayoutParams
        //   Result: No Effect      
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, 0, 0, 0);

        // Test (2): Setting all padding to 0 for btnA
        //   Result: No Effect
        Button btnA = new Button(this);
        btnA.setText("Btn A");
        btnA.setPaddingRelative(0, 0, 0, 0);
        btnA.setBackground(getResources().getDrawable(R.drawable.test_background));
        testLayout.addView(btnA, params);

        // Test (3): Setting minimum height of the View btnB to a value smaller than the height of the text
        //   Result: No Effect
        Button btnB = new Button(this);
        btnB.setText("Btn B");
        btnB.setMinimumHeight(1);
        btnB.setBackground(getResources().getDrawable(R.drawable.test_background));
        testLayout.addView(btnB, params);

        // Test (4): Setting minimum height of the TextView for btnC to a value smaller than the height of the text
        //   Result: No Effect
        Button btnC = new Button(this);
        btnC.setText("Btn C");
        btnC.setMinHeight(1);
        btnC.setBackground(getResources().getDrawable(R.drawable.test_background));
        testLayout.addView(btnC, params);

        // Test (5): Setting minimum height of both the View & the TextView for btnD 
        //           to a value smaller than the height of the text
        //   Result: Button appears to implement padding as defined in the 9Patch
        Button btnD = new Button(this);
        btnD.setText("Btn D");
        btnD.setMinimumHeight(1); 
        btnD.setMinHeight(1);
        btnD.setBackground(getResources().getDrawable(R.drawable.test_background));
        testLayout.addView(btnD, params);

        // Test (6): Manually setting the padding for btnE from the 9Patch as per dandc87's suggestion.
        //   Result: No Effect
        Button btnE = new Button(this);
        btnE.setText("Btn E");
        btnE.setBackground(getResources().getDrawable(R.drawable.test_background));
        NinePatchDrawable img = (NinePatchDrawable) getResources().getDrawable(R.drawable.test_background);
        Rect padding = new Rect();
        img.getPadding(padding);
        btnE.setPadding(padding.left, padding.top, padding.right, padding.bottom);  
        testLayout.addView(btnE, params);

        // Test (7): Using the 9Patch with an ImageButton instead of a Button
        //   Result: Button appears to implement padding as defined in the 9Patch
        ImageButton btnF = new ImageButton(this);
        btnF.setImageResource(android.R.drawable.ic_menu_add);
        btnF.setBackground(getResources().getDrawable(R.drawable.test_background));
        testLayout.addView(btnF, params);

    }
}

Upvotes: 2

Views: 717

Answers (1)

dandc87
dandc87

Reputation: 1106

To get the padding from the 9patch, you could try:

NinePatchDrawable img = (NinePatchDrawable) getResources().getDrawable(R.drawable.my_9p);
Rect padding = new Rect();
img.getPadding(padding);
//padding now contains the padding

You can then use padding to set the padding of the Button with setPaddingRelative()

Upvotes: 1

Related Questions