1

I want to wrap an ImageView inside a LinearLayout so that I can center a group of views. However, the original image needs to be scaled down to fit in the ImageView, and the original size expands the LinearLayout, despite my use of adjustViewBounds="true" and an enclosing FrameLayout as suggested by previous questions on SO.

The desired layout should look like this,

but the observed layout looks like this,

as produced by the XML below:

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

        <LinearLayout
            android:layout_width="wrap_content"
            app:layout_heightPercent="32%"
            android:orientation="horizontal"
            android:background="#b44343"
            android:layout_centerHorizontal="true"
            android:layout_alignParentTop="true">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Sample Text"/>
            <FrameLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#5555ae">
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:background="#2c8c4c"
                    android:src="@drawable/spades_icon"
                    android:adjustViewBounds="true"
                    android:scaleType="centerInside"/>
            </FrameLayout>
        </LinearLayout>
    </android.support.percent.PercentRelativeLayout>

I can't use the other suggestion of setting android:maxHeight="100dp" because I need the height to be relative to that of the screen.

Onik
  • 19,396
  • 14
  • 68
  • 91
David Brakman
  • 113
  • 1
  • 8

3 Answers3

0

I see that you have added android:adjustViewBounds="true".

You can combine that with android:maxWidth="60dp"

So your imageView should look like this.

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:background="#2c8c4c"
                android:src="@drawable/spades_icon"
                android:adjustViewBounds="true"
                android:maxWidth="60dp"
                android:scaleType="centerInside"/>

You can change the max width to any number you want.

Dishonered
  • 8,449
  • 9
  • 37
  • 50
  • Did you mean maxHeight? I specified that I couldn't set `maxHeight` to a fixed value because it would defeat the purpose of using the PercentRelativeLayout. Similarly, I can't fix `maxWidth` because having `adjustViewBounds` causes the height to change, like [this](http://oi66.tinypic.com/sb0byw.jpg). – David Brakman May 14 '17 at 15:59
0

Things you can do:

1) Set a specific width / height to the FrameLayout enclosing the ImageView and set android:scaleType to centerInside, fitCenter, or fitXY for the ImageViwe.

2) Programatically, in your activity, after onCreate, in onResume for example, you can get the LayoutParams and change the width and height of the ImageView doing you own scaleing. I take this aproach when I scale against the screen widht or height at run time.

EDIT 1

Example of second alternative:

public class TestActivity extends AppCompatActivity {

    ImageView imgView;

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

        imgView = (ImageView) findViewById(R.id.imgview);

    }

    @Override
    protected void onResume() {
        super.onResume();
        ViewGroup.LayoutParams params = imgView.getLayoutParams();
        params.width = 100;
    }
}

Notes: The width is expressed in pixel. To get the display metrics: How to get screen display metrics in application class

To establish a relative width for the ImageView, get the width of the display and calculate the desireed % as the width of the image.

Community
  • 1
  • 1
Juan
  • 5,525
  • 2
  • 15
  • 26
  • (1) In my post, I mentioned that I am not willing to fix a specific width/height and that I am currently using `android:scaleType="centerInside"`. (2) I have seen posts about getting `LayoutParams`, but `getLayoutParams().height` returns 0 even in the MWE's `onResume().` (There is no confounding code in the MWE aside from what Android Studio auto-generates for an Empty Activity.) – David Brakman May 14 '17 at 16:53
  • I am adding an example in my answer. I have just ran it and it does change the width. – Juan May 14 '17 at 17:43
  • The example changes the width, but not appropriately. The desired layout depicted has an `ImageView` that matches the height of its parent and scales the width to preserve aspect ratio. To scale the width dynamically _without_ resorting to a fixed size requires retrieving information about the dimensions of views, which `getLayoutParams()` in `onResume()` is not doing. – David Brakman May 14 '17 at 18:42
  • You have tried setting the FrameLayout height to match_parent as well as the ImageView right? – Juan May 14 '17 at 19:30
  • Yes; I've left it as match_parent, but it didn't seem to change the situation. – David Brakman May 14 '17 at 19:32
0

Based on this answer to another question, a solution that removes the whitespace in the LinearLayout while preserving the height and aspect ratio of the image is:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    LinearLayout layout = (LinearLayout) findViewById(R.id.mLinearLayout);
    ImageView imageView = (ImageView) findViewById(R.id.mImageView);
    TextView textView = (TextView) findViewById(R.id.mTextView);

    layout.getLayoutParams().width = textView.getWidth()+imageView.getWidth();
    layout.requestLayout();
}

EDIT:
Based on @Juan's answer and these instructions, the following code also achieves the desired result:

@Override
protected void onResume() {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    this.getWindowManager()
        .getDefaultDisplay()
        .getMetrics(displayMetrics);

    ViewGroup.LayoutParams params = imgView.getLayoutParams();
    params.height = (int)Math.floor(displayMetrics.heightPixels * 0.32);
}
Community
  • 1
  • 1
David Brakman
  • 113
  • 1
  • 8