Skip to content Skip to sidebar Skip to footer

Android - Keep Aspect Ratio On Background Image On Default Button

Is there any way to maintain the aspect ratio of a drawable when applied as background on a Button (cannot use ImageButton (need possibility for text on the Button), cannot use set

Solution 1:

I faced the same problem recently for setting the background image of an ImageView. The solution I came up with works with any View, so it should cover Button as well.

The issue is that View always stretches its background to the full extent of View's width and height, no matter the scaling of the Drawable provided as background. As your report on failing to provide specialized Drawables suggests, this cannot be counteracted by any means of scaling an image prior to setting it as background because View would simply take the image dimensions, whatever they are, and scale them again independently to fill the View's area.

My solution takes a different approach based on the fact that if we can provide a background image with same aspect ratio as the View's, there would be no distortion.

Function scaleKeepingAspect() below takes an image resource and answers a BitmapDrawable that contains the original image scaled to a desired width and height. The scaling is performed in a way that the aspect ratio of the original image is kept, and eventual remaining spaces to fit the desired box are filled with transparent pixels. The original image is centered in the result image.

private BitmapDrawable scaleKeepingAspect(Resources res, int id, int dstWidth, int dstHeight){

    Bitmap b = (newBitmapFactory()).decodeResource(res, id);
    float scaleX = (float) dstWidth / b.getWidth();
    float scaleY = (float) dstHeight / b.getHeight();
    float scale = scaleX < scaleY ? scaleX : scaleY;
    int sclWidth = Math.round(scale * b.getWidth());
    int sclHeight = Math.round(scale * b.getHeight());
    b = Bitmap.createScaledBitmap(b, sclWidth, sclHeight, false);
    int[] pixels = newint[sclWidth * sclHeight];
    b.getPixels(pixels, 0, sclWidth, 0, 0, sclWidth, sclHeight);
    b = Bitmap.createBitmap(dstWidth, dstHeight, b.getConfig());
    b.setPixels(pixels, 0, sclWidth, (dstWidth - sclWidth) / 2, (dstHeight - sclHeight) / 2, sclWidth, sclHeight);
    returnnewBitmapDrawable(res, Bitmap.createBitmap(b));

}

A proper place to make use of scaleKeepingAspect() in setting the background of a View is during layout change events, so the background is updated properly when the bounds of the View change due to layout processing. To do so, assuming (a) your View is identified by myView in your layout xml, and (b) your background image is file res/drawable/background.png, do the following:

  1. Declare your Activity as an implementor of View.OnLayoutChangeListener interface:

    publicclassMyActivityextendsActivityimplementsView.OnLayoutChangeListener {
    
        ...
    
    }
    
  2. Register your Activity as a listener to layout changes of your View:

    @OverridepublicvoidonCreate(Bundle savedInstanceState) {
    
        ...
    
        myView = (View) findViewById(R.id.myView);
        myView.addOnLayoutChangeListener(this);
    
        ...
    
    }
    
  3. Detect for View layout updates in the layout change handler, and update its background when needed:

    @OverridepublicvoidonLayoutChange(View v,
            int left, int top, int right, int bottom,
            int oldLeft, int oldTop, int oldRight, int oldBottom) {
    
        if (left == right || top == bottom || (
                left == oldLeft && top == oldTop &&
                right == oldRight && bottom == oldBottom))
            return;
    
        switch (v.getId()) {
    
            case R.id.myView:
    
                v.setBackground(
                    scaleKeepingAspect(
                        getResources(),
                        R.drawable.background,
                        v.getWidth(),
                        v.getHeight()));
                break;
    
        }
    
    }
    

Post a Comment for "Android - Keep Aspect Ratio On Background Image On Default Button"