Search code examples
androidandroid-constraintlayoutconstraintlayout-guideline

Add margin to guideline objects inside ConstraintLayout


Is this possible?

I want following:

  • HEADER of a defined height (e.g. 64dp)
  • 4 rows of evenly distributed heights (25% of view height MINUS header height <= this is the problematic detail)

Can I somehow achieve this with a ConstraintLayout?

Problem

I want to add a header of a fixed height and I want the the percentage constraints do not calculate their percentages based on the ConstraintLayouts height but on the remaining space inside the ConstraintLayout after substracting the header.

Important Note

Yes, I can wrap the whole ConstraintLayout inside a LinearLayout but I'm interested in a ConstraintLayout only based solution.

Edit 1

To make it more clear, I want following:

h_full... full height of ConstraintLayout
h_header... full height of header

Vertical arrangement of views should look like following:
    - HEADER - y = 0
    - VIEW 1 - y = h_header
    - VIEW 2 - y = h_header + (h_full - h_header) / 4
    - VIEW 3 - y = h_header + (h_full - h_header) / 4 * 2
    - VIEW 4 - y = h_header + (h_full - h_header) / 4 * 3

Let's assume following:
   h_full = 1000
   h_header = 100
   space for views = 1000 - 100 = 900 (this is the base for the percentages!)
  h_view = 900 / 4 = 225

Then we get following:
    - HEADER - y = 0
    - VIEW 1 - y = 100
    - VIEW 2 - y = 100 + 225
    - VIEW 3 - y = 100 + 225 * 2
    - VIEW 4 - y = 100 + 225 * 3

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="match_parent">

    <!-- Guidelines -->
    <!-- 3 horizontal guidelines -->

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline_horizontal1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.25" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline_horizontal2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline_horizontal3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.75" />

    <!-- Views - HEADER -->

    <View
        android:id="@+id/header"
        android:layout_width="0dp"
        android:layout_height="64dp"
        android:layout_marginLeft="@dimen/calender_cell_padding"
        android:layout_marginTop="@dimen/calender_cell_padding"
        android:layout_marginRight="@dimen/calender_cell_padding"
        android:layout_marginBottom="@dimen/calender_cell_padding"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

     <!-- Views - 4 Views, evenly distrubuted vertically -->
     
    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/guideline_horizontal1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/guideline_horizontal2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline_horizontal1" />

    <View
        android:id="@+id/view3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/guideline_horizontal3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline_horizontal2" />

    <View
        android:id="@+id/view4"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline_horizontal3" />

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • I found the solution by building my layout with LinearLayouts and then convert it to a ConstraintLayout and then I made some adjustments - and it worked.

    The solution is to use biderectional bindings without guidelines - this way you can define a header of a fixed height and biderictionally bind all views below to each other with a height of 0dp and this will have the effect that all views below the header share the remaining space equally with each other.

    Here's my full layout, it's a week view with a header (the header has a fixed size, the day cells do use the remaining space equally):

    Screenshot

    enter image description here

    Layout

    <?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="match_parent">
    
        <!-- Header -->
    
        <com.google.android.material.card.MaterialCardView
            android:id="@+id/mcvDetails"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/calender_cell_padding"
            android:layout_marginTop="@dimen/calender_cell_padding"
            android:layout_marginEnd="@dimen/calender_cell_padding"
            android:layout_marginBottom="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toTopOf="@+id/btFriday"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
            <LinearLayout
                android:id="@+id/llDayDetails"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:orientation="vertical">
    
                <TextView
                    android:id="@+id/tvInfos"
                    android:gravity="center_horizontal"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Infos" />
    
            </LinearLayout>
    
        </com.google.android.material.card.MaterialCardView>
    
        <!-- Row 1 - Mon / Fri -->
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btMonday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_padding"
            android:layout_marginEnd="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toBottomOf="@+id/btFriday"
            app:layout_constraintEnd_toStartOf="@+id/btFriday"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btFriday"
            app:vcc_label="@string/monday" />
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btFriday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_half_padding"
            android:layout_marginTop="@dimen/calender_cell_half_padding"
            android:layout_marginEnd="@dimen/calender_cell_padding"
            android:layout_marginBottom="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toTopOf="@+id/btSaturday"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btMonday"
            app:layout_constraintTop_toBottomOf="@+id/mcvDetails"
            app:vcc_label="@string/friday" />
    
        <!-- Row 2 - Tue / Sat -->
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btTuesday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_padding"
            android:layout_marginEnd="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toBottomOf="@+id/btSaturday"
            app:layout_constraintEnd_toStartOf="@+id/btSaturday"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btSaturday"
            app:vcc_label="@string/tuesday" />
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btSaturday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_half_padding"
            android:layout_marginTop="@dimen/calender_cell_half_padding"
            android:layout_marginEnd="@dimen/calender_cell_padding"
            android:layout_marginBottom="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toTopOf="@+id/btSunday"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btTuesday"
            app:layout_constraintTop_toBottomOf="@+id/btFriday"
            app:vcc_label="@string/saturday" />
    
        <!-- Row 3 - Wen / Sun -->
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btWednesday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_padding"
            android:layout_marginEnd="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toBottomOf="@+id/btSunday"
            app:layout_constraintEnd_toStartOf="@+id/btSunday"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btSunday"
            app:vcc_label="@string/wednesday" />
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btSunday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_half_padding"
            android:layout_marginTop="@dimen/calender_cell_half_padding"
            android:layout_marginEnd="@dimen/calender_cell_padding"
            android:layout_marginBottom="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toTopOf="@+id/btUnused"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btWednesday"
            app:layout_constraintTop_toBottomOf="@+id/btSaturday"
            app:vcc_label="@string/sunday" />
    
        <!-- Row 4 - Thu -->
    
        <com.michaelflisar.iron.feature.workoutlog.views.calendarview.cell.CalendarCellView
            android:id="@+id/btThursday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_padding"
            android:layout_marginEnd="@dimen/calender_cell_half_padding"
            app:layout_constraintBottom_toBottomOf="@+id/btUnused"
            app:layout_constraintEnd_toStartOf="@+id/btUnused"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/btUnused"
            app:vcc_label="@string/thursday" />
    
        <View
            android:id="@+id/btUnused"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="@dimen/calender_cell_half_padding"
            android:layout_marginTop="@dimen/calender_cell_half_padding"
            android:layout_marginEnd="@dimen/calender_cell_padding"
            android:layout_marginBottom="@dimen/calender_cell_padding"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btThursday"
            app:layout_constraintTop_toBottomOf="@+id/btSunday" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>