nhaarman
nhaarman

Reputation: 100468

Background drawables define view size

For the sake of clarity, this question has been edited significantly.

Let's say I have a .png resource of 100x100px:
enter image description here

I want to use that image as a background for my TextViews, which size is determined by its content, which is variable at runtime. Especially, I want that image to tile when the TextView size is larger than 100x100px, and I want it to be cropped when the TextView is smaller than 100x100px.

The latter seems to be a difficult one.

Example code

I have a drawable resource bg_tile.xml:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/bg"
    android:tileMode="repeat" />

My layout file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:background="@drawable/bg_tile"
        android:text="Short text"
        android:textSize="20sp" />

    <TextView android:layout_margin="8dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_tile"
        android:text="Long text long text long text long text long text long text long text long text long textlong text long text long text long text long text long text long text long text long textlong text long text long text long text long text long text long text long text long text "
        android:textSize="20sp" />

</LinearLayout>

What's happening

Here is a screenshot of the result of this code, and one of what I would expect / what I want: enter image description here

As you can see, the tiling part works, and the bottom tile is being cut off. However, when the TextView is smaller than the background, the TextView takes the size of the background.

Suggested solutions

How can I achieve my goal?

Upvotes: 17

Views: 8063

Answers (5)

Ray Lee
Ray Lee

Reputation: 51

This method works for me.

  1. clear the TextView background
  2. (in postRunnable) save TextView width and height
  3. (in postRunnable) set new background to TextView
  4. (in postRunnable) set width and height to TextView

Example

public void setTextViewBg(final TextView textView, final Drawable newBgDrawable) {
    textView.setBackground(null);
    textView.post(new Runnable() {
        @Override
        public void run() {
            int width = textView.getWidth();
            int height = textView.getHeight();
            textView.setBackgroundDrawable(newBgDrawable);
            LinearLayout.LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams();
            layoutParams.width = width;
            layoutParams.height = height;
        }
    });
}

Hope it helps~

Upvotes: 1

Streets Of Boston
Streets Of Boston

Reputation: 12596

I have not tried this myself, but you could try this idea/hack/workaround:

The minimum height/width of a View (TextView) is determined by its background drawable (amongst other things). It uses the background Drawable's getMinimumHeight() and getMinimumWidth() to determine the View's minimum height and width.

It looks like you want the View's minimum height and width to be 0 (excluding padding) and the View's width/height should be based only on the View's content (in your case, the TextView's text).

Try this in the onCreate of your Activity or the onCreateView of your Fragment, where you get a hold of the TextView you are trying to 'fix'. Let's call this TextView 'tv':

TextView tv; 
...
...
tv = (TextView)...findViewById(...);
....

// Swap the 'standard' bitmap background with one that has no minimum width/height.
BitmapDrawable background = (BitmapDrawable)tv.getBackground(); // assuming you have bg_tile as background.
BitmapDrawable newBackground = new BitmapDrawable(background.getBitmap) {
    @Override
    public int getMinimumWidth() {
        return 0;
    }

    @Override
    public int getMinimumHeight() {
        return 0;
    }
};
newBackground.setTileModeXY(background.getTileModeX(), background.getTileModeY());
tv.setBackgroundDrawable(newBackground);
...
...

Upvotes: 14

Jason Robinson
Jason Robinson

Reputation: 31294

Try this:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/bg_light"
    android:tileMode="repeat"
    android:gravity="clip_vertical|clip_horizontal" />

Additional options: http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap

Edit: I Read the documentation, this won't work with tileMode set:

android:tileMode

Keyword. Defines the tile mode. When the tile mode is enabled, the bitmap is repeated. Gravity is ignored when the tile mode is enabled.

If you know the size of the Views ahead of time and know that it would clip, you could have one Bitmap-XML for tileMode and another for gravity, then use the appropriate one. Not ideal, unfortunately.

Upvotes: 0

user1717693
user1717693

Reputation: 41

You could always use:

android:layout_width="match_parent"
android:layout_height="match_parent"

Upvotes: 0

NathanTempelman
NathanTempelman

Reputation: 1387

I'm guessing your problem is right here:

android:layout_width="wrap_content" android:layout_height="wrap_content"

It sets the width to wrap the content, and the content includes the background image. I'm not sure what the context of your view is, but if you can just set the height from code, or from the xml file, your problem should go away. You might also want to add android:scaleType="centerCrop" or centerInside as Houcine mentioned if the background still doesn't display to your liking.

If you tell us the context of these vague views, we can probably give you more information.

Upvotes: 0

Related Questions