6

I have a TextView and a square ImageView that I would like to show in a horizontal linear layout. Each should take half of the parent view's width and the height should fit the content (i.e. the image). The text should be centered vertically.

Additional constraint is that the image should not grow beyond a given maxWidth (= maxHeight), and excess width should be made available to the TextView. Obviously, this conflicts with the 50/50 rule above. Is there a way to prioritize the constraints, i.e. allow the image to take half of the space unless it exceeds a given size?

desired outcome

These are layouts I tried:

The first one nicely stretches the left side to the available space. But the image takes more than half of the width as its layout_weight is not specified (as in image below).

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center_vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Some text."/>
    </LinearLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxWidth="200dp"
        android:adjustViewBounds="true"
        android:src="@drawable/image" />
</LinearLayout>

without <code>layout_weight</code>

When I add layout_weight to the ImageView it always takes half of the width and ignore the maxWidth (see image below).

    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:maxWidth="200dp"
        android:adjustViewBounds="true"
        android:src="@drawable/image" />

with <code>layout_weight</code>

Enclosing the ImageView in another LinearLayout enables the maxWidth again, but the enclosing LinearLayout still takes half of the available space (see image below).

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="right">

        <ImageView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:maxWidth="200dp"
            android:adjustViewBounds="true"
            android:src="@drawable/image" />
    </LinearLayout>

using enclosing <code>LinearLayout</code>

Another option I have found for similar scenarios is to use a RelativeLayout with an invisible view as a center divider, but that locks the division to 50/50 (or wherever the divider is placed).

Community
  • 1
  • 1
  • The `TextView` filling the other screen and all is easy.. the conflicting condition where each `View` (*TextView and ImageView*) takes half of the parent's width makes it difficult.. – AL. Mar 17 '16 at 06:40

3 Answers3

2

Okay, gonna go on ahead and post the xml I created, it's pretty much simple, it does most of your conditions.. One thing I'm having trouble with is the part where each view takes half of the parent view's width. Hope this still helps you in some way.

sample_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="2dp"
    android:background="@android:color/darker_gray">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/img_sample"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="2dp"
        android:layout_toLeftOf="@id/img_sample"
        android:background="@color/colorPrimary"
        android:gravity="center_vertical"
        android:text="Some text." />

    <ImageView
        android:id="@id/img_sample"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="2dp"
        android:adjustViewBounds="true"
        android:maxWidth="200dp"
        android:src="@drawable/sample_img" />

</RelativeLayout>

Here is a sample screenshot: enter image description here

If ever you figure out how to the the half of each thing, kindly comment it here, It'd be nice to know about it for possible future use. :)

PS: Have you considered doing the half of each thing programatically? Like checking the LayoutParams then dynamically setting weightSum and the layout_weights.

Sample Image retrieved from this link

AL.
  • 36,815
  • 10
  • 142
  • 281
  • 1
    Thank you for the effort and great illustration. You managed to simplify my first example with the same result. That I can directly apply. But, as you noted, it does not fully meet the requirements. The way I solved it for now is avoiding the problem by creating different views for landscape and portrait. True, it can also be done programmatically. I might have the wrong expectations. :) –  Mar 17 '16 at 07:02
  • 1
    Unless someone comes up with an xml way of doing this I suspect that handling it programmatically is indeed the correct answer: set the `layout_weight` of the `ImageView`if the container's width exceeds two times `maxWidth`. I'll give it a couple of days before I set the check mark. –  Mar 17 '16 at 07:20
  • 1
    @jerry No worries. Good luck. :) As much as possible, I would also like to see an implementation via xml only, might be able to use it someday. :D – AL. Mar 17 '16 at 07:24
  • 1
    Marked as answer for simplifying the original layout and the conclusion that the last bit may indeed have to be done programmatically. Or - as in my specific case - create separate layouts for different screen orientations. –  Mar 17 '16 at 15:04
0
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentTop="true"
        android:layout_weight="1"
        android:adjustViewBounds="true"
        android:background="@color/blue"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_margin="5dp"
        android:layout_toStartOf="@id/imageView"
        android:background="@color/colorPrimary"
        android:padding="10dp"
        android:text="Some text. " />
</RelativeLayout>

Here's what it looks like

shibapoo
  • 1,909
  • 3
  • 16
  • 22
  • Hmm, but there really is only one case. The layout should adapt to parent view's width. –  Mar 17 '16 at 05:56
  • Try using RelativeLayout as parent, then for your image view gave it a layout_weight=1, alignparentRight = true. – shibapoo Mar 17 '16 at 06:02
  • I was initially using Relative layout with the hidden divider `View` as described in the answer I linked to. This gave pretty much the same result as the 3rd try of mine. I started from there now, removed the divider and applied `Layout_weight=1` and `alignParentRight=true`. There might be something else wrong, but the image now takes almost the entire width with equal margins on both sides, covering the text. The size is probably limited by the size of the image iself. –  Mar 17 '16 at 06:22
  • One alternative (and what I'm doing for the time-being) is, in a way, related to what you say in your answer. Mainly I wanted to address portrait and landscape views. Got a little frustrated as I could not easily figure out a way to dynamically adapt a single layout. So I ended up defining separate layouts for both orientations. Luckily, that is very easy for Android. –  Mar 17 '16 at 06:28
  • Sorry, I missed that update. Tried but it does not work. I suspect that, when `layout_weight` is defined for the image, the `maxWidth` property (which is missing here) is ignored. –  Mar 17 '16 at 06:46
  • Could it be that it looks different in your screenshot because you are using a smaller image? –  Mar 17 '16 at 07:09
0

It won't be a perfect solution in term of performance. But you can achieve it by playing with FrameLayout and ImageView.

Here is the output: enter image description hereenter image description here

Layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/textGray"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/skyBlue">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@android:color/white">

                <ImageView
                    android:id="@+id/imageView4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:maxWidth="200dp"
                    android:src="@drawable/ic_settings"
                    android:visibility="invisible" />

                <TextView
                    android:id="@+id/TextView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:text="!" />
            </FrameLayout>

            <ImageView
                android:id="@+id/imageView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:maxWidth="200dp"
                android:src="@drawable/ic_settings" />
        </LinearLayout>
    </FrameLayout>
</LinearLayout>

In order to achieve desire behaviour, You would have to set same images to both imagesviews in this layout. one of them is invisble, It is just helping to make parent with same width and heights which would lead us to create TextView with same dimensions.
Note: If you want to change textView alignment, you can do it with layout_gravity or gravity.

Ahmad Raza
  • 2,850
  • 1
  • 21
  • 37
  • Thank you. That is an interesting approach. I dropped your code directly into my view - just changed color and image names. Two problems: 1. The text section does not expand when there is room for it (it should take more than 50%). 2. Using a larger image, the height of the entire group is set by the source image size while the width of each side is still 50%. –  Mar 17 '16 at 09:03
  • 1. you can achieve that behavior by playing with textview's and its parent view's gravities. 2. we are using maxWidth=200dp for imageView. if you add maxHeight's value, it won't expand to full height. – Ahmad Raza Mar 17 '16 at 12:34
  • @jerry: That sample give you an idea to achieve required functionality. I would suggest you to play with it and modify it as required. Happy Coding :) – Ahmad Raza Mar 17 '16 at 12:45
  • Thank you. `maxWidth` and `maxHeight` have no effect in this layout. So I'm not sure about this but I will keep trying. :) –  Mar 17 '16 at 14:12
  • Please note: You would have to set maxWidth and maxHeight of both imageViews in this layout otherwise it won't work. – Ahmad Raza Mar 17 '16 at 14:15
  • Realized that what's actually missing here is `adjustViewBounds="true"`. Adding that, the max dimensions are working. Still, the `layout-weight` fixes the division to 50/50. –  Mar 17 '16 at 14:28