dvkch
dvkch

Reputation: 1109

ConstraintLayout chain with fixed aspect ratio

I'm trying to build an activity with 3 imageViews according to the following layout:

   <------W------->         <------W-------->
^  +---------------+--------+---------------+
|  |               |        |               |
|  |               |        |               |
H  |       A       |   B    |      C        |
|  |               | (1:3)  |               |
|  |               |        |               |
v  +---------------+--------+---------------+

I tried multiple solutions and could never find one that works. The last one uses :

While I would expect that the solver would make the desired layout instead it seems the chain defines a similar width to all views as seen in the screenshot.

I also tried using a LinearLayout but it doesn't seem possible to fix the aspect ratio of items inside one.

enter image description here

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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=".MainActivity">

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_blue_bright"
        app:layout_constraintBottom_toTopOf="@+id/guideline"
        app:layout_constraintDimensionRatio=""
        app:layout_constraintEnd_toStartOf="@+id/imageView2"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@mipmap/ic_launcher" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_blue_bright"
        app:layout_constraintBottom_toTopOf="@+id/guideline"
        app:layout_constraintDimensionRatio="1:3"
        app:layout_constraintEnd_toStartOf="@+id/imageView3"
        app:layout_constraintStart_toEndOf="@+id/imageView1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@mipmap/ic_launcher" />

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_blue_bright"
        app:layout_constraintBottom_toTopOf="@+id/guideline"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@mipmap/ic_launcher" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.3333" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.6666666666" />

</android.support.constraint.ConstraintLayout>

Thanks a lot!

Upvotes: 8

Views: 5240

Answers (2)

Juan
Juan

Reputation: 5589

I think the ConstraintLayout won't be able to handle all the restrictions put upon the middle view in terms of height or width, aspect ration, and boundaries, so this solution has part implemented in the xml and a final adjustment programatically.

It separates the three images with guidelines, and when the layout is rendered, it recalculates the position of the guidelines.

Layout

<android.support.constraint.ConstraintLayout 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:id="@+id/mainLayout"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.Guideline
        android:id="@+id/guidelineV33"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.3333" />

    <android.support.constraint.Guideline
        android:id="@+id/guidelineH33"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.3333" />

    <android.support.constraint.Guideline
        android:id="@+id/guidelineH66"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.6666" />

    <ImageView
        android:id="@+id/ivA"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/guidelineH33"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/guidelineV33"/>

    <ImageView
        android:id="@+id/ivB"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintLeft_toRightOf="@id/guidelineH33"
        app:layout_constraintRight_toLeftOf="@id/guidelineH66"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/guidelineV33"
         />
    <ImageView
        android:id="@+id/ivC"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintLeft_toRightOf="@id/guidelineH66"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/guidelineV33"/>


</android.support.constraint.ConstraintLayout>

Activity

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.ViewTreeObserver;

public class SO50626509Activity extends AppCompatActivity {

    private static final String TAG = SO50626509Activity.class.getName();

    ConstraintLayout cl;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.so50626509_layout);
        cl = findViewById(R.id.mainLayout);
        ViewTreeObserver observer = cl.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                adjustLayout();
                cl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
    }


    private void adjustLayout(){
        int height = (int) (cl.getMeasuredHeight() * 0.3333);
        int width = cl.getMeasuredWidth();
        int middleWidth = height / 3;
        int g33 = (width - middleWidth) / 2;
        int g66 = g33 + middleWidth;


        ConstraintSet set = new ConstraintSet();
        set.clone(cl);
        set.setGuidelinePercent(R.id.guidelineH33,((float) g33 / (float) width));
        set.setGuidelinePercent(R.id.guidelineH66,((float) g66 / (float) width));
        set.applyTo(cl);
    }

}

Upvotes: 0

Cheticamp
Cheticamp

Reputation: 62831

There are probably several approaches to doing what you ask. Here is one approach:

enter image description here

The key to this layout is to set up the center image first as defined in the XML. Once the center image is established, it becomes easier to define the left and right images.

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageViewLeft"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/imageCenter"
        app:layout_constraintEnd_toStartOf="@+id/imageCenter"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/imageCenter"
        app:srcCompat="@color/colorPrimary" />

    <ImageView
        android:id="@+id/imageCenter"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="W,1:3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_percent="0.33"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@color/colorAccent" />

    <ImageView
        android:id="@+id/imageViewRight"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/imageCenter"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageCenter"
        app:layout_constraintTop_toTopOf="@+id/imageCenter"
        app:srcCompat="@color/colorPrimary" />
</android.support.constraint.ConstraintLayout>

Upvotes: 5

Related Questions