How do I keep the aspect ratio on image buttons in android?
Asked Answered
P

9

37

I have 5 square ImageButtons that I want to have lined up side by side on the bottom of the screen. I have each one set (different id's) as:

        <ImageButton
         android:id="@+id/box1" 
         android:layout_width="fill_parent"
         android:layout_height="wrap_content" 
         android:layout_gravity="center"
         android:adjustViewBounds="true"
         android:scaleType="fitXY"
         android:layout_weight="1"
         android:layout_margin="1dp"
         /> 

and I have the background assigned in main java like this:

    int[] imageIds = new int[] {R.id.box1,R.id.box2,R.id.box3,R.id.box4,R.id.box5};
    for(int i = 0; i<5; i++){
        imageButtons[i] = (ImageButton) findViewById(imageIds[i]);
        imageButtons[i].setBackgroundResource(R.drawable.blank);
    }

What I would like to have it do is scale the width to fit neatly side-by-side at the bottom of the screen (which it does now ok), but have the height automatically scale to match the width as well. is this possible? I don't want to use setImageSource because then it puts a border around the imagebutton.

Processional answered 11/1, 2011 at 11:12 Comment(0)
L
35
   <LinearLayout
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:id="@+id/layoutButtons">

     <com.package.SquareButton         
        android:layout_height="fill_parent"
        android:layout_width="0dip"          
        android:layout_weight="1"

        <ImageView
        android:id="@+id/box1"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        android:layout_height="wrap_content"
        android:layout_width="0dp"          
        android:layout_weight="1" 
        android:layout_marginLeft="5dp" 
        android:layout_marginRight="5dp"/>

      </com.package.SquareButton>

      <com.package.SquareButton         
        android:layout_height="fill_parent"
        android:layout_width="0dip"          
        android:layout_weight="1"

        <ImageView
        android:id="@+id/box2"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent"          
        android:layout_marginLeft="5dp" 
        android:layout_marginRight="5dp"/>

</com.package.SquareButton>

   .........          
 </LinearLayout>

And then add this custom button class:

public class SquareButton extends LinearLayout {

    public SquareButton(Context context) {
        super(context);
    }

    public SquareButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    // This is used to make square buttons.
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }
}
London answered 2/11, 2011 at 10:50 Comment(7)
finally! this did it for me. it seems to me that there should have been a simpler method, but judging that it took almost a year to get an answer that worked for me, i think this is it. thank you so much!Processional
Isn't it better if SquareButton directly derives from ImageButton instead of a LinearLayout? The UI thread would appreciate it, I'm sure :)Sorghum
Can you explain me the difference?London
Do you know you'd make an image keep its' aspect ratio and align to the parent right instead of the center?Dragoman
Better name it SquareLayoutPurine
This solution does not work properly if MeasureSpec.getMode(widthMeasureSpec) is MeasureSpec.AT_MOST (this happened to me when I put different size of the same image in the different drawable folders).Altricial
This would be a great answer if it was combined with explanationsTannate
M
34

I have had a similar headache in trying to get my buttons in a row. The solution I found was to use ImageButton and the android:src property (setImageSource in code) in combination with android:background="@null"

As I understand it the background of an image button doesn't get affected by the adjustViewBounds, it is only the imageView which you set in android:src.

The default behavior is then to give you a square button with the imageView in the middle of it. You can override that by setting the background to @null, which leaves you with only the image.

You can then use either a LinearLayout or a table to layout your buttons. I did everything in XML and used the following layout to create a row of two buttons at the bottom of the screen that scale up or down maintaining the aspect ratio with different device screens sizes. Hope this helps.

<TableLayout    
    android:id="@+id/tableLayout2"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_marginBottom="20dip"
    android:stretchColumns="*">

    <TableRow>

     <ImageButton
        android:id="@+id/button_one"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
        android:layout_weight="0.5"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"  
        android:onClick="clickOne"
        android:background="@null"
        android:src="@drawable/button_one_drawable" />

    <ImageButton
        android:id="@+id/button_two"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
        android:layout_weight="0.5"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"  
        android:onClick="clickTwo"
        android:background="@null"
        android:src="@drawable/button_two_drawable" />

    </TableRow>      
</TableLayout>
Marquettamarquette answered 1/11, 2011 at 13:0 Comment(5)
This is the answer I've been looking for! Your explanation helped me understand ImageButton a lot better. :DDurable
This is the best answer. Works great if you would like to fix the height and desire the width to autoscale based on the aspect ratio. +1Anurag
Nicely done. After messing with GridLayout for a day, this worked perfectly. Thx.Carcass
This one worked better for me than the SquareButton class, as that class still had some cropping issues for me, presumably because it isn't recognised as an "image type" in the layout manager. Thanks both.Tarboosh
Worked great! but I couldn't set background to null, so I made it transparent: android:background="#00000000"Waffle
S
12

Instead of

android:scaleType="fitXY" 

use:

android:scaleType="centerInside"

EDIT1: Try this one:

    <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/layoutToInflateButtons"
            >
    <ImageButton 
        android:id="@+id/box1"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"          
        android:layout_weight="1"          
        android:layout_margin="1dp"
        />          
    </LinearLayout>
Sympathizer answered 11/1, 2011 at 11:55 Comment(2)
Clever answer (and without messing with sub-classes), thank you!Detect
i have to add android:layout_width="wrap_content" android:layout_height="0dp" to ImageButton to make work this code.Fracture
G
3

You can use Google's Percent Relative Layout that helps you to manage view aspect ratio.

You can use it like this

     <android.support.percent.PercentRelativeLayout
             xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:app="http://schemas.android.com/apk/res-auto"
             android:layout_width="match_parent"
             android:layout_height="match_parent">

         <ImageButton
             android:id="@+id/box1" 
             android:layout_width="fill_parent"
             android:layout_height="wrap_content" 
             android:layout_gravity="center"
             android:adjustViewBounds="true"
             android:scaleType="fitXY"
             app:layout_aspectRatio="100%"
             android:layout_weight="1"
             /> 
     </android.support.percent.PercentFrameLayout>

The aspect ratio 100% will make width same as height.

example:

android:layout_width="300dp"
app:layout_aspectRatio="178%"

a width 178% of the height. This is the format the layout_aspectRatio expects

You can read it in detail here

Gadgeteer answered 3/8, 2016 at 13:19 Comment(0)
S
1

I am sure you want to have that 5 buttons of EQUAL width/height. If this is the case then take LinearLayout and put all those 5 buttons with layout_width="0dip" and layout_weight="1"

For example:

<LinearLayout
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:id="@+id/layoutButtons">

    <ImageButton 
        android:id="@+id/box1"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        android:layout_height="wrap_content"
        android:layout_width="0dip"          
        android:layout_weight="1"/>

    <ImageButton 
        android:id="@+id/box2"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        android:layout_height="wrap_content"
        android:layout_width="0dip"          
        android:layout_weight="1"/>    

   .........          
 </LinearLayout>
Skippie answered 31/10, 2011 at 6:35 Comment(1)
nope, i tried your code and it looks like this: i.imgur.com/3piDS.jpg it should look like this imgur.com/4FFzD (ignoring the added margins). the only way i got it working was do kind of cheat with changing the margins and stuff around, but when i go to a different display size like a tablet, it gets all screwed up. so now i am going back to my original code and trying to get this to work. the pictures are 90x90px if that helps.Processional
L
1

After checking Google I/O sample application from this year I've found that Google is using dimen values for specifying varios heights or widths based on the screen type. For details you can check the source code from http://code.google.com/p/iosched/.

You can specify the height of the button for exemple in values-xhdpi or values-sw720dp as:

 <resources>
    <dimen name="button_height">50dp</dimen>
</resources>

And then you can just use this dimen value when specifying the height:

android:layout_height="@dimen/button_height"
Lanthanide answered 6/10, 2012 at 22:39 Comment(0)
F
0

Set the width of the ImageButtons to fill_parent and use scaletype fitStart for the images that hug the left margin, and fitEnd for the ones on the right. Should do the trick, at least as far as your example image goes. You may have some spacing issues if the proportional width of the images exceed the screen width, but it should work for you.

Farmyard answered 4/11, 2011 at 13:44 Comment(0)
L
0
ViewGroup.LayoutParams params = imageButtonName.getLayoutParams();
// Changes the height(or width) and width(or height) to the specified 
params.height = layout.getWidth();
Lattimer answered 21/9, 2013 at 8:56 Comment(0)
K
0

Look into making a custom ImageButton. I like this because its one class. Here is a button that adjusts its height based on the image aspect ratio. I imagine you can tweak to your needs :

public class AspectImageButton extends ImageButton {


public AspectImageButton(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    this.getDrawable();

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int width = getMeasuredWidth();

    Drawable d=this.getDrawable(); //grab the drawable

    float fAspectRatio=(float)d.getIntrinsicWidth()/(float)d.getIntrinsicHeight();

    float fHeight=(float)width/fAspectRatio;//get new height

    setMeasuredDimension(width, (int)fHeight);
}

public AspectImageButton(Context context, AttributeSet attrs) {
    super(context, attrs);

    // TODO Auto-generated constructor stub
}

public AspectImageButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    // TODO Auto-generated constructor stub
}

}

then in xml just use it like this:

<com.package.AspectImageButton
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:src="@drawable/home_1b"
                android:background="@null"
                android:scaleType="fitXY"
                android:adjustViewBounds="true" />
Kilogram answered 20/5, 2015 at 16:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.