14. Apr 2021
AndroidAndroid development tips: Constraint Layout helpers II. part
I brought you the second part of an article about Constraint Layout Helpers, which are type of ViewGroup, which allows you to create complex layouts. Full power of Constraint Layouts comes from his helpers, so i've prepared the article about them.
In the first part of the introduction to Constraint Layout Helpers, I introduced Group, Guidline, Layer and Barrier. If you haven't seen them yet, don't forget to visit the first part!
Placeholder
Placeholder is helper which can help to position another views (that's where it's name comes from - it's "holding place" for view). When you call setContentId() method on placeholder object somewhere in your code, placeholder objects become the content view. If content view exists on the screen already, it will be treated as gone on its original location after setContentId() call.
E.g. when some of the upper circles is clicked, placeholder.setContentId() is called, placeholder becomes the clicked view (clicked view moves to placeholder's position, inherits placeholder's constraints).
val onClickListener = View.OnClickListener { view ->
TransitionManager.beginDelayedTransition(content) //For animation effect
placeholder.setContentId(view.id) //Set view to placeholder
}
image1.setOnClickListener(onClickListener)
image2.setOnClickListener(onClickListener)
image3.setOnClickListener(onClickListener)
<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"
android:id="@+id/content"
android:paddingTop="16dp">
<ImageView
android:id="@+id/image1"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/background_badge_green"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/image2"/>
<ImageView
android:id="@+id/image2"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/background_badge_red"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/image1"
app:layout_constraintEnd_toStartOf="@id/image3"/>
<ImageView
android:id="@+id/image3"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/background_badge_black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/image2"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/placeholder"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Don't miss my #goodroidtips I. or II. ,articles about useful tips and tricks for Android developers.
Flow
Similar to Group, Flow takes views ids into constraint_referenced_ids attribute and automatically creates Chain behavior between them. Chain behavior (way how views overflow the Flow) is determined by wrapMode attribute of Flow.
//Default behavior of Flow, just creates chain between referenced views
//If views do not fit into Flow, they will overflow the Flow
app:flow_wrapMode="none"
OR
//If views do not fit into Flow, they jump on another line and take place evenly
app:flow_wrapMode="chain"
OR
//If views do not fit into Flow, they jump on another line and align to create rows and columns
app:flow_wrapMode="aligned"
As we said, Flow automatically creates chain between it's elements. Chain style can be configured by flow_horizontalStyle or flow_verticalStyle attribute based on Flow's orientation. Behavior of chain style is basically the same as for chains.
For horizontal Flow
app:flow_horizontalStyle="spread" //Default
OR
app:flow_horizontalStyle="packed"
OR
app:flow_horizontalStyle="spread_inside"
First and last chain in the Flow can have different style attributes as others e.g. for the first chain we define flow_firstHorizontalStyle="spread_inside" for the last chain we define flow_lastHorizontalStyle="packed". All the others chains in the middle took default flow_horizontalStyle="spread" because we did not defined anything.
<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">
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:flow_wrapMode="chain"
app:flow_maxElementsWrap="2"
app:flow_firstHorizontalStyle="spread_inside"
app:flow_lastHorizontalStyle="packed"
app:constraint_referenced_ids="circle1, ..., circle9"/>
//Include 9 circles
<include
android:id="@+id/circle1"
layout="@layout/circle"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Flow can be customized by many other attributes e.g.
//Orientation of Flow, can be vertical or horizontal
android:orientation="vertical"
//Maximum number of elements in one row or column
app:flow_maxElementsWrap="3"
//Vertical or horizontal gap between referenced views
app:flow_horizontalGap="20dp"
app:flow_verticalGap="20dp"
Bonus
Circular positioning
Circular positioning attributes allows you to constraint view to another view at specified angle and distance. Important attributes when we want to circularly position views are
app:layout_constraintCircle="@id/baseImage" //Constrained base view
app:layout_constraintCircleRadius="90dp" //Radius of the circle
app:layout_constraintCircleAngle="45" //Degree of the circle on which we display the view
E.g. positioning image1, image2 and image 3 around baseImage in 0, 45 and 90 degree.
<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">
<ImageView
android:id="@+id/image1"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/background_badge_green"
app:layout_constraintCircle="@id/baseImage"
app:layout_constraintCircleRadius="90dp"
app:layout_constraintCircleAngle="0"/>
<ImageView
android:id="@+id/image2"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/background_badge_green"
app:layout_constraintCircle="@id/baseImage"
app:layout_constraintCircleRadius="90dp"
app:layout_constraintCircleAngle="45"/>
<ImageView
android:id="@+id/image3"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/background_badge_green"
app:layout_constraintCircle="@id/baseImage"
app:layout_constraintCircleRadius="90dp"
app:layout_constraintCircleAngle="90"/>
<ImageView
android:id="@+id/baseImage"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:src="@drawable/background_badge_black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Resources: https://developer.android.com/reference