32

I created a background image bitmap for a view and now the view is being stretched to the size of the background image....

is this normal?

<?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@drawable/green"
        android:tileMode="repeat"/>

here's how I apply it to my view

v.setBackgroundResource(R.drawable.backgroundgreen);

for instance...

if the image is 500px in height and the view is 200px in height(being set wrap_content as height) after setting the image as background my view becomes 500px in height...

trejder
  • 17,148
  • 27
  • 124
  • 216
Mars
  • 4,197
  • 11
  • 39
  • 63

8 Answers8

36

I have faced this same problem.

If the background image has a size that is bigger than the view's size, the view's size will change to match the image's size.

Solution


  1. Put the view inside a Relative Layout.
  2. Remove the background image.
  3. Add an ImageView before the View inside the Relative Layout
  4. Set the src of the ImageView to your background image

    <RelativeLayout
        .
        .
        . >
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/yourViewId"
            android:layout_alignRight="@+id/yourViewId"
            android:layout_alignTop="@+id/yourViewId"
            android:layout_alignBottom="@+id/yourViewId"
            android:adjustViewBounds="true" 
            //this will allow the image to resize with same proportions
            android:src="@drawable/yourDrawable" />
    
        <YourView
            android:id="@+id/yourViewId"
            .
            ..
            ... />
    
      </RelativeLayout>
    

This all can be done in code of course.

Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
  • 2
    I can't get this to work... still shows the full image... using your exact same code :s am I missing something? – Mars Nov 23 '11 at 13:55
  • did you wrap_content both the `RelativeLayout` and `YourView` ? – Sherif elKhatib Nov 23 '11 at 13:57
  • In the RelativeLayout: `android:layout_width="fill_parent"` why? – Sherif elKhatib Nov 23 '11 at 13:59
  • cause I want the background to fill the screen vertically.. it's the height of the view thats a problem for me... :( //edit just tried to set it to wrap content too but still the same... – Mars Nov 23 '11 at 14:02
  • oh you have `android:background="@drawable/background"` in the RelativeLayout – Sherif elKhatib Nov 23 '11 at 14:05
  • oops you're right.. but removing that still didn't fix it... are you sure this has worked for you? and this way the background isn't even tileling :s – Mars Nov 23 '11 at 14:40
  • I am pretty sure I used this. The codes are not here. Look, you should adjust the ImageView using these properties: `android:layout_alignParentTop`, `android:layout_alignParentBottom`, `android:layout_alignParentLeft`, `android:layout_alignParentRight`. In this way it will be resized according to the parent, which will be adjusted to fit yourView. – Sherif elKhatib Nov 23 '11 at 14:52
  • sounds logical but it's still not working for me... pretty weird... :s – Mars Nov 23 '11 at 16:38
  • @mars Please check the answer. Try to set the imageview to take the size of your view. I think this should work. I am not really able to try this here because I got alotttttttttt of work heheh. Frankenstein thank you v.v.v. much – Sherif elKhatib Nov 28 '11 at 07:49
  • 1
    Once additional comment as I just used this sample for my code: Depending on the aspect ratio of your view and your background image and your desired target design you may eventually need to add android:scaleType="fitXY" to the ImageView to make sure your background gets completely covered. – Nantoka Jun 15 '13 at 22:29
29

According to me, the problem you are facing is not a problem, it is the way how Android is used to design the layouts.

This means that you can set the height and width with 3 default constant values:

FILL_PARENT
Special value for the height or width requested by a View. FILL_PARENT means that the View wants to be as big as its parent, minus the parent's padding if any. This value is deprecated starting in API Level 8 and replaced by MATCH_PARENT.

MATCH_PARENT
Special value for the height or width requested by a View. MATCH_PARENT means that the view wants to be as big as its parent, minus the parent's padding if any. Introduced in API Level 8.

WRAP_CONTENT
Special value for the height or width requested by a View. WRAP_CONTENT means that the View wants to be just large enough to fit its own internal content, taking its own padding into account.

Now, when you are setting the View's height/width to WRAP_CONTENT, you are allowing the view to take that much size that is sufficient to show to view's content. The background image is also the View's content, hence you view will be shown of as much size as the image. That's not a problem, that's how it's shown.

Okay, but in your situation that's an issue for you because you have a background to show and view should not be stretched for that. I can suggest few ways:

  1. First and very obvious: make correctly sized images and keep them in different drawable folders.

  2. Specify the size of view not using constants, but in DP. If it becomes necessary, make different layout XML files for different sizes and keep them in layout folders.

  3. You can use a very useful thing for design layout is layout weight.

Community
  • 1
  • 1
MKJParekh
  • 34,073
  • 11
  • 87
  • 98
  • 3
    Frankenstein you are right. However in android it seems that regardless of the layout_width and layout_height, the BACKGROUND will always determine the size of a view :( ! Your solution is right but I think that they should have allowed the opposite logic: the view determines the size of the background. and again and again thanks! – Sherif elKhatib Nov 28 '11 at 07:48
  • 1
    The last link (layout weight) is broken. Could you please explain what is the layout weight technique about in the answer itself? – Piovezan Apr 07 '15 at 12:16
  • 1
    @Piovezan According to this article http://developer.android.com/training/improving-layouts/optimizing-layout.html using layout_weight can be especially expensive as each child needs to be measured twice. So, I think the opposite of MKJParekh, layout_weight is not recommended if you can use another technique – Jorge Casariego Jun 23 '15 at 18:07
  • I also believe so that's why I have already put it on the 3rd priority. Anyways you are absolutely correct. @JorgeCasariego – MKJParekh Jul 08 '15 at 13:25
3

I suggest to create a wrapper layout and put the background image in there. i'm using it that way and fits very nicely. see example below

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/settingstab_scroll"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:scrollbars="vertical"
    android:background="@drawable/wareninja_wallpaper_img"
    >
<!-- your layouts and components goes here -->
</ScrollView>


...
Social Coding @ AspiroTV

Yilmaz Guleryuz
  • 9,313
  • 3
  • 32
  • 43
2

The reason is quite simple. You gotta see the View::getSuggestedMinimumWidth/Height method.

protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}

protected int getSuggestedMinimumHeight() {
    return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
}

Seeing that, you may know why the background makes a view bigger, especially why assign a BitmapDrawable to it.

and the simple solution is to wrap that Drawable (eg. BitmapDrawable), then returns 0 for getMinimumHeight() and getMinimumWidth(), and better to override getIntrinsicHeight() and getIntrinsicWidth() to returns -1.

support-v7 has a DrawableWrapper which delegates calls to another drawable when necessary. you can extends that one and override methods talked above.

and if you don't use support-v7 (WoW! you are awesome), copy that class to your project is also fine.

https://android.googlesource.com/platform/frameworks/support/+/1949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65/v7/appcompat/src/android/support/v7/internal/widget/DrawableWrapper.java

landerlyoung
  • 1,693
  • 17
  • 14
1

It's working for me.

< ?xml version="1.0" encoding="utf-8"?>
 < LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="@+id/LinearLayoutTest">    

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.prueba);


    ((LinearLayout)findViewById(R.id.LinearLayoutTest)).setBackgroundResource(R.drawable.greenrepeat);
}

in your code, what is v? It has params to fill_parent?

AntPachon
  • 1,152
  • 12
  • 14
  • v is a custom listitem in a listview, its root view is a linearlayout... in your test is the view bigger or smaller than the background? because my background is bigger than the view.. – Mars Nov 20 '11 at 22:54
0

One good solution that is working perfectly in my case is extending the View and overriding onMeasure().

Here is the steps to do:

  1. Create an own class and extend the View you want to use, here for example I will use Button.
  2. Override the method onMeasure() and insert the code at the bottom. This will set the background resource after the first measure has been done. For the second measure event, it will use the already measured paramters.

Example code for a custom view which extends Button (change Button to the View you would like to extend)

public class MyButton extends Button {

    boolean backGroundSet = false;

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

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

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);          
    }

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

        if(backGroundSet) {
            setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
            return;
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        backGroundSet = true;
        setBackgroundResource(R.drawable.button_back_selector);

    }
}

The only thing to change here is the type of view you want to extend and in the onMeasure() method the background resource you want to use for the view.

After that, just use this view in your layout xml or add it programatically.

Chris623
  • 2,464
  • 1
  • 22
  • 30
0

I modify Sherif elKhatib's code, now this works for me:

  1. if we want background picture be stretched as view picture:

         <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
    
             <ImageView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_alignStart="@+id/yourViewId"
                 android:layout_alignTop="@+id/yourViewId"
                 android:layout_alignEnd="@+id/yourViewId"
                 android:layout_alignBottom="@+id/yourViewId"
                 android:scaleType="fitXY"
                 android:src="@drawable/bg_very_big_picture" />
    
             <LinearLayout
                 android:id="@+id/yourViewId"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
    
  2. if we want background picture not to be stretched, but to be cutted to fit view picture:

         <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
    
             <ImageView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_alignStart="@+id/yourViewId"
                 android:layout_alignTop="@+id/yourViewId"
                 android:layout_alignEnd="@+id/yourViewId"
                 android:layout_alignBottom="@+id/yourViewId"
                 android:scaleType="centerCrop"
                 android:src="@drawable/bg_very_big_picture" />
    
             <LinearLayout
                 android:id="@+id/yourViewId"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
    
hyyou2010
  • 791
  • 11
  • 22
0

Don't use android:tileMode="repeat". Is your green drawable bigger or smaller than your view? Could add more details?

slybloty
  • 6,346
  • 6
  • 49
  • 70
  • my background is bigger than the view but the view might be stretched if more content is added later... – Mars Nov 20 '11 at 22:53