Layout, View, ViewGroup Part - II

Power of Constraints!

Recap

As we have done LinearLayout in the past now we know the major factor that a view would prioritize LinearLayout is when:

  • The view that we should make is simple.
  • The view can be easily developed by vertical and horizontal orientation.
  • View does not have overlapping sub-views.
  • Can be quickly made without thinking more about responsiveness.
  • Can be imagined in a stack.

What if the view is complex? What if the view we should make has overlapping and inter-dependent sub-views?

Then we should use another view group knows as Constraint Layout.

ConstraintLayout

A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.

Let's see the super basics of ConstraintLayout.

image.png

The image above shows views A,B,C inside a constraint layout. Constraint layout is totally about the relativeness of the view to its environment views and parent.

Here the view A is constrained-top (vertical) to its parent and constrained-start (horizontal) to its parent. The A now has its horizontal and vertical constraint fulfilled and can be said to have valid constraint inside a ConstraintLayout.

To make a View be valid inside constraint layout, a view must ALWAYS have at least ONE HORIZONTAL (start / end) and ONE VERTICAL (top / bottom) constraint.

View B also seems to be valid in the constraint layout as it as top, start and end constraints. But View C only has start and end constraints. This is cause view to be invalid has C cannot define its vertical constraint in the constraint view.

To solve this we now define the top constraint for C as

image.png

Now this will be a valid ConstraintLayout with all views constrained.

Examples

To make constraint between two view components (a textview with another textview) we have to define id for the views. Below example shows a view with id

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

 <TextView
      android:id="@+id/top_text"
      android:textSize="27sp"
      android:layout_marginTop="24dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      android:text="Android App Constraint"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  • Here the TextView has id has top_text
  • Since it is inside a ConstraintLayout it has constraints fullfilment as:
    • app:layout_constraintStart_toStartOf="parent"
    • app:layout_constraintEnd_toEndOf="parent"
    • app:layout_constraintTop_toTopOf="parent"

Adding another view below the top_text view in constraint layout

If we add the following code below the top_text component;


{Previous TextView Component Here}

 <EditText

      android:id="@+id/input_username"
      android:hint="Username"
      android:layout_marginTop="30dp"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintTop_toBottomOf="@id/top_text"
      android:layout_marginHorizontal="30dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>

</androidx.constraintlayout.widget.ConstraintLayout>

We can now have

  • A new EditText view with id as input_username
  • has constraint below the top_text as app:layout_constraintTop_toBottomOf="@id/top_text" which defines that this view must have its TOP joined to BOTTOM of the top_textview
  • horizontal constrained are defined normally as app:layout_constraintStart_toStartOf="parent" and app:layout_constraintEnd_toEndOf="parent"

Flexibility

If we want to put views in horizontal or vertical or nested forms, while using LinearLayout we should change orientations every time but for ConstraintLayout, just defining relative constraints is enough. ConstraintLayout solves the complexity of a view in a very flexible manner and we use this ViewGroup in 80% of the cases.

Examples in Git

You can refer to ConstraintLayout examples in learning MAD github project under the 02-constraint-layout branch.

Complete Example

Suppose you as a developer have to design a view given as image

Visualization

  • So on the first look I am seeing that the whole card component has some kind of radius, this is possible to achieve by using something called CardView
  • Then I can see that there are two sections, blue section with some details on it and white section with ImageView, some details and Buttons
  • So I will be making this view using the above visualized components along with ConstraintLayout

So the Appointment Card Component needs to be designed with:

  • ConstraintLayout
  • ImageView
  • CardView
  • MaterialButton (2021)

You can make a new file to make this component by right clicking on layout folder inside res folder and selecting layout resource file. Give it a name as layout_card_component.

XML Code

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">

    <androidx.cardview.widget.CardView

        android:id="@+id/main_card_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:cardCornerRadius="15dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

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

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#345EDC">


                <TextView
                    android:id="@+id/text_appointment"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="20dp"
                    android:text="Appointment Request"
                    android:textColor="@color/white"
                    android:textSize="20sp"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />


                <ImageView
                    android:id="@+id/image_clock"
                    android:layout_width="25dp"
                    android:layout_height="25dp"
                    android:layout_marginTop="20dp"
                    android:layout_marginBottom="20dp"
                    android:src="@color/white"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintStart_toStartOf="@id/text_appointment"
                    app:layout_constraintTop_toBottomOf="@id/text_appointment" />


                <TextView
                    android:id="@+id/text_date"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="20dp"
                    android:text="12 Jan 2020, 8am - 10am"
                    android:textColor="@color/white"
                    android:textSize="17sp"
                    app:layout_constraintBottom_toBottomOf="@id/image_clock"
                    app:layout_constraintStart_toEndOf="@id/image_clock"
                    app:layout_constraintTop_toTopOf="@id/image_clock" />


                <ImageView
                    android:layout_width="10dp"
                    android:layout_height="30dp"
                    android:layout_marginTop="10dp"
                    android:layout_marginEnd="25dp"
                    android:src="@color/white"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="@id/text_appointment" />


            </androidx.constraintlayout.widget.ConstraintLayout>


            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/avatar"
                    android:layout_width="60dp"
                    android:layout_height="60dp"
                    android:layout_marginStart="30dp"
                    android:layout_marginTop="30dp"
                    android:src="@color/purple_200"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

                <TextView
                    android:id="@+id/name"
                    android:layout_width="100dp"
                    android:layout_height="wrap_content"
                    android:lines="2"
                    android:maxWidth="80dp"
                    android:text="Louis Patterson"
                    android:textSize="22sp"
                    app:layout_constraintBottom_toBottomOf="@id/avatar"
                    app:layout_constraintEnd_toStartOf="@id/info"
                    app:layout_constraintHorizontal_bias="0.05"
                    app:layout_constraintStart_toEndOf="@id/avatar"
                    app:layout_constraintTop_toTopOf="@id/avatar" />

                <ImageView
                    android:id="@+id/info"
                    android:layout_width="30dp"
                    android:layout_height="30dp"
                    android:layout_marginEnd="30dp"
                    android:src="@color/purple_200"
                    app:layout_constraintBottom_toBottomOf="@id/avatar"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="@id/avatar" />

                <com.google.android.material.button.MaterialButton
                    android:id="@+id/accept"
                    android:layout_width="150dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="30dp"
                    android:layout_marginBottom="30dp"
                    android:backgroundTint="#FF345EDC"
                    android:text="ACCEPT"
                    app:cornerRadius="10dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toStartOf="@+id/decline"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@id/avatar" />

                <com.google.android.material.button.MaterialButton
                    android:id="@+id/decline"
                    android:layout_width="100dp"
                    android:layout_height="wrap_content"
                    android:backgroundTint="#9E9E9E"
                    android:text="DECLINE"
                    app:cornerRadius="10dp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toEndOf="@+id/accept"
                    app:layout_constraintTop_toTopOf="@id/accept" />


            </androidx.constraintlayout.widget.ConstraintLayout>

        </LinearLayout>

    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

image.png

I have not used any images or extra views to make sure that when you copy and paste the above code will run without any problems.

Assignment 03

image.png

Try Making this page!

Best of Luck~

Submitting assignments must be done via github, please make the repository public so that I can see the task.