ConstraintLayout spread views inside with same width - android

I want to have a horizontal alignment of four buttons with these conditions:
their texts are 25%, 50%, 75%, 100% (so the last one will be wider)
they should have same width
they should spread the through the remaining space
Is it possible to achieve this using ConstraintLayout?
To demonstrate what I exactly want, take a look at current state of my layout (which is ok):
The buttons currently are set to have a width of 25 percent of the parent and there's a static margin between them (implemented using a LinearLayout). What is the problem? It's possible in small screens that the margin cause the last button to be truncated (like the image below), or in large screens the buttons be so large.
So I want the spread behavior of ConstraintLayout besides width of the last button be wrap_content and width of other buttons be set equal to the last button.

Thanks to #cheticamp and his answer provided here, the best way of achieving the desired behavior would be writing a simple ConstraintHelper which sets width of all the children to the maximum among them.
class MaxWidthConstraint #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
override fun updatePostMeasure(container: ConstraintLayout) {
val maxWidth =
referencedIds.asSequence().map { container.getViewById(it) }
.map { container.getViewWidget(it) }
.map { it.width }
.max() ?: 0
referencedIds.asSequence().map { container.getViewById(it) }
.map { container.getViewWidget(it) }
.forEach { it.width = maxWidth }
}
}
So the layout code would be:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="HardcodedText">
<Button
android:id="#+id/btn_25"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="25%"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="#id/btn_50"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_50"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="50%"
app:layout_constraintEnd_toStartOf="#id/btn_75"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="#id/btn_25"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_75"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="75%"
app:layout_constraintEnd_toStartOf="#id/btn_100"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="#id/btn_50"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_100"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="100%"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="#id/btn_75"
app:layout_constraintTop_toTopOf="parent" />
<com.myapplication.widgets.MaxWidthConstraint
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="btn_25,btn_50,btn_75,btn_100"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

So this is what i came up with:
<?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">
<Button
android:id="#+id/tv_25"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:text="25%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/tv_50"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/tv_50"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:text="50%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toRightOf="#id/tv_25"
app:layout_constraintRight_toLeftOf="#id/tv_75"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/tv_75"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:text="75%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toRightOf="#id/tv_50"
app:layout_constraintRight_toLeftOf="#id/tv_100"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/tv_100"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="100%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toRightOf="#id/tv_75"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Explanation: I've used app:layout_constraintHorizontal_chainStyle="spread".Using chain takes the margin into account while spreading the views evenly.

Using chain style spread might be you got your expected 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">
<Button
android:id="#+id/btn_25"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/entercode_default"
android:text="25%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btn_50"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_50"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/entercode_default"
android:text="50%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btn_75"
app:layout_constraintStart_toEndOf="#+id/btn_25"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_75"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/entercode_default"
android:text="75%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btn_100"
app:layout_constraintStart_toEndOf="#+id/btn_50"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_100"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/entercode_default"
android:text="100%"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/btn_75"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

Custom Android CardView Dialog Preview different

I want to display a custom dialog using a cardView to display some information. The preview looks exactly like it should and is previewed in Android Studio the following:
The quick_preview.xml xml for this is
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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/SensorOverView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:minWidth="300dp"
android:minHeight="300dp"
android:visibility="visible"
app:cardCornerRadius="20dp"
app:cardElevation="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="160dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/scrollView2">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/subTitleLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="#+id/titleLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="#+id/btnClose"
android:layout_width="72dp"
android:layout_height="24dp"
android:layout_weight="1"
android:background="#color/background_light_elevation_1"
android:text="Button"
android:textColor="#78909C"
app:icon="#drawable/ic_baseline_close_24"
app:iconTint="#color/app_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/txtSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="Lorem Ipsum"
android:textSize="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btnClose"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/titleLayout"
android:layout_width="0dp"
android:layout_height="45dp"
app:layout_constraintBottom_toTopOf="#+id/viewContent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/subTitleLayout">
<TextView
android:id="#+id/txtTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="Lorem ipsum"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/rejectOrAddLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/viewContent">
<Button
android:id="#+id/btnReject"
android:layout_width="72dp"
android:layout_height="56dp"
android:background="#FF5454"
android:text="Button"
app:icon="#drawable/ic_baseline_close_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btnAdd"
app:layout_constraintStart_toEndOf="#+id/txtInfo"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnAdd"
android:layout_width="72dp"
android:layout_height="56dp"
android:layout_weight="1"
android:background="#00D7A0"
android:text="Button"
app:icon="#drawable/ic_baseline_check_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/btnReject"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/txtInfo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:maxHeight="56dp"
android:text="Select to delete/add"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btnReject"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/viewContent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toTopOf="#+id/rejectOrAddLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/titleLayout"
tools:listitem="#layout/sensor_content_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
The dialog uses a custom class QuickPreviewDialog.kt
class QuickPreviewDialog(context: Context) : Dialog(context) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.requestWindowFeature(Window.FEATURE_NO_TITLE)
this.setCancelable(false);
this.setContentView(R.layout.sensor_quick_preview);
this.getWindow()?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
}
and is invoked by:
val dialog = QuickPreviewDialog(this)
dialog.show()
But the result is the following and I don't know what's wrong:
To achieve what you want without changing too much code,a simple solution i would suggest you to use is putting a LinearLayout as your cardView's parent
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<androidx.cardview.widget.CardView
android:id="#+id/SensorOverView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:minWidth="300dp"
android:minHeight="300dp"
android:visibility="visible"
app:cardCornerRadius="20dp"
app:cardElevation="10dp">
//Rest of your view
</androidx.cardview.widget.CardView>
</LinearLayout>
And just like that you see your dialog's size as same as you want it to be
Android dialogs tend to have their own ideas about how large they should be. We will address the dialog size, but first you will need to change how the minimum height and width is specified in the CardView.
Change
android:minWidth="300dp"
android:minHeight="300dp"
to
app:minWidth="300dp"
app:minHeight="300dp"
If you just make this change, you should see your entire layout crammed into the small dialog window. This is the correct way to specify minimum sizes for CardViews.
You will have to programmatically adjust the dialog window's size by doing something like the following to override the defaults:
val padding = 160
val dialog = QuickPreviewDialog(this)
dialog.show()
// Set the window's size only after dialog.show()
val widthHeight = getScreenSize()
dialog.window?.setLayout(widthHeight.first - padding, widthHeight.second - padding)
private fun getScreenSize() =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
Pair(
displayMetrics.widthPixels,
displayMetrics.heightPixels
)
} else {
val bounds = windowManager.currentWindowMetrics.bounds
Pair(bounds.width(), bounds.height())
}

Specify max constraint percentage on a view

Problem
Specify Max Constraint percentage for any view.
For example -
In a case below I have a 2 left views and 2 right views.
I want to constraint that right can acquire maximum of 50% percent of the entire width.
The left items holds precedence which means they can acquire as much space they like. So, if any of the left item is large enough it can shift right items and shrink them down.
I tried the following approach but this doesn't seem to work i.e when right1 or right2 text gets long enough it takes the preference and acquires more than 50% width.
Currently, constraint layout probably doesn't support this but is there any way to achieve this?
XML
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/section_item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/left_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="#id/left_2"
app:layout_constraintEnd_toStartOf="#id/l_container"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread"
tools:text="Leftsadasdasdadsdasdasdhsjakjdhaskkjdhdjakskjhkjdashkjddasdasdsaadsdasd1" />
<TextView
android:id="#+id/left_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/l_container"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="#id/left_1"
app:layout_constraintTop_toBottomOf="#id/left_1"
tools:text="Left2" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/right_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="l_container" />
<LinearLayout
android:id="#+id/l_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="wrap"
app:layout_constraintWidth_max="wrap"
app:layout_constraintWidth_percent="0.5">
<TextView
android:id="#+id/right_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="#+id/right_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Right1"
tools:visibility="visible" />
<TextView
android:id="#+id/right_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="#id/left_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintTop_toBottomOf="#+id/right_1"
tools:text="Right2"
tools:visibility="visible" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I took some liberties to simplify the layout for this illustration, but you should be able to reconstruct your layout from the following.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/left_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="false"
app:layout_constraintEnd_toStartOf="#id/right_barrier"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Not so long" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/right_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="right_1" />
<TextView
android:id="#+id/right_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="#id/right_barrier"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_max="wrap"
app:layout_constraintWidth_percent="0.5"
android:text="very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very " />
</androidx.constraintlayout.widget.ConstraintLayout>
which produces this:
Increasing the text length in left_1 causes the left view encroach into the right half of the screen.
layout_constrainedWidth and layout_constraintWidth_max are what's of interest in the layout.

Android ConstraintLayout: Views not respecting margins

I am attempting to create a layout where various pieces of data are separated by a line (View), but the design requires an equal top and bottom spacing from the line. I am trying to use margins to accomplish this, but I am not getting the results I expected. Based on the official documentation, as long as the constraints are set for the margin direction, they should be respected. For some reason the top margin gives us the correct spacing, however the bottom margin does not give any spacing at all. I have created a sample containing only the pertinent layout axml to reproduce, along with a large enough margin to visualize the issue:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
<TextView android:text="NAME"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_name_label"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<TextView android:text="Your Name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_name"
app:layout_constraintTop_toBottomOf="#+id/account_name_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<View
android:id="#+id/line1"
app:layout_constraintTop_toBottomOf="#+id/account_name"
app:layout_constraintBottom_toTopOf="#+id/account_joined_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="#000000"
android:layout_marginTop="100dp"
android:layout_marginBottom="100dp"
/>
<TextView android:text="JOINED"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_joined_label"
app:layout_constraintTop_toBottomOf="#+id/line1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<TextView android:text="January 1, 2019"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_joined"
app:layout_constraintTop_toBottomOf="#+id/account_joined_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
</android.support.constraint.ConstraintLayout>
The above results in the following, visually:
Now, I can add the android:layout_marginTop="100dp" to the first TextView after the line View to "fix" this, however I want to reuse the styles for the line View, without having to worry about remembering to add a top margin to whatever happens to be the first View after the line View. What am I missing?
Update: Here is what the layout SHOULD look like:
You need to connect the bottom of account_joined to the bottom of parent and the bottom of account_joined_label to the top of account_joined. So you can try this one:
<?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"
android:padding="20dp">
<TextView android:text="NAME"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_name_label"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView android:text="Your Name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_name"
app:layout_constraintTop_toBottomOf="#+id/account_name_label"
app:layout_constraintRight_toRightOf="parent" />
<View
android:id="#+id/line1"
app:layout_constraintTop_toBottomOf="#+id/account_name"
app:layout_constraintBottom_toTopOf="#+id/account_joined_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="#000000"
android:layout_marginTop="100dp"
android:layout_marginBottom="100dp"/>
<TextView android:text="JOINED"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_joined_label"
app:layout_constraintTop_toBottomOf="#+id/line1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="#+id/account_joined" />
<TextView android:text="January 1, 2019"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/account_joined"
app:layout_constraintTop_toBottomOf="#+id/account_joined_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Some info before the code:
When you use something like android:layout_marginTop="100dp" you are making your layout to a non-responsive one.
Why: In android, different phones got dofferent screen size and what may look good on 1 device with 100dp margin may not look good on another device.
So if possible try not to use large values as fixed sizes, the next part of the question will explain how to handle this.
Here is where the fun begins:
You can simply use Guidelines to fix your margin problems - it will be responsive to all screen sizes and won't have hardcoded value like 120dp.
All you have to do is to constraint "NAME" to the top constraint and "JOINED" to the bottom constraint like this:
<?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">
<TextView
android:id="#+id/account_name_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="NAME"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline9" />
<TextView
android:id="#+id/account_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="Your Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/account_name_label" />
<View
android:id="#+id/line1"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="8dp"
android:background="#000000"
app:layout_constraintBottom_toTopOf="#+id/account_joined_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/account_name" />
<TextView
android:id="#+id/account_joined_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="JOINED"
app:layout_constraintBottom_toTopOf="#+id/guideline8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/account_joined"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="January 1, 2019"
app:layout_constraintBottom_toTopOf="#+id/account_joined_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<android.support.constraint.Guideline
android:id="#+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.85" />
<android.support.constraint.Guideline
android:id="#+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
</android.support.constraint.ConstraintLayout>
And it will look like this:
Now don't be scared, your layout looks ok - it's just my lame lame skills in editing photos (check this on your device).
The important thing is that you can change the look of your layout by changing the value of this line in your guidelines:
app:layout_constraintGuide_percent="0.15"
If anything was not understandable feel free to ask.

Split a Relative Layout with wrap_content

I got a RelativeLayout like this:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
Inside this Layout, there are some TextView and other stuff, through which the height of the Layout is defined, because it is set to wrap_content like you can see above.
Now I want to have have two Views in the RelativeLayout who share the space(in respect to width) but fill the whole Layout. The purpose behind this is, that I want to have two onClickListener. In other words: I want to kind of split the layout in two Views next to another (horizontally).
I tried to put a LinearLayout inside the RelativeLayout like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="#+id/togoTrueTrigger"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="#+id/togoFalseTrigger"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
It takes the whole with of the RelativeLayout and one TextView takes the left 50% and the other one the right 50%. That is exactly what I want. BUT I also want them to take the whole Height.
What I can't do: Set the Height of the LinearLayout to match_parent. This is not possible, because the whole thing is inside another layout and this would adjust the Height in relation to this layout.
EDIT: This is my new approach
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp">
<TextView
android:id="#+id/togoTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pickup"
android:textAppearance="#style/itemConfiguration"
app:layout_constraintLeft_toLeftOf="parent"/>
<com.bhargavms.podslider.PodSlider
android:id="#+id/togoSwitch"
android:layout_width="75dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:numberOfPods="2"
app:selectedPodColor="#color/colorAccent"
app:mainSliderColor="#color/colorPrimary"
app:podColor="#ffffff"
android:layout_centerInParent="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="#+id/togoFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vor Ort"
android:textAppearance="#style/itemConfiguration"
app:layout_constraintRight_toRightOf="parent"/>
<View
android:id="#+id/togoTrueTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<View
android:id="#+id/togoFalseTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
Unfortunately this still doesn't work.
EDIT:
Here is a sketch of what I want. The first picture is the layout and the second shows the same layout with a blue and a red view. These Views are the ones I try to create.
So there are three views inside of the main layout and two views with 50% width obove of them. I believe this is Your answer:
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/togoTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pickup"
android:textAppearance="#style/itemConfiguration"
app:layout_constraintLeft_toLeftOf="parent" />
<com.bhargavms.podslider.PodSlider
android:id="#+id/togoSwitch"
android:layout_width="75dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mainSliderColor="#color/colorPrimary"
app:numberOfPods="2"
app:podColor="#ffffff"
app:selectedPodColor="#color/colorAccent" />
<TextView
android:id="#+id/togoFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vor Ort"
android:textAppearance="#style/itemConfiguration"
app:layout_constraintRight_toRightOf="parent" />
<View
android:id="#+id/togoTrueTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#44ffff00"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent=".5" />
<View
android:id="#+id/togoFalseTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#4400ff00"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent=".5" />
</android.support.constraint.ConstraintLayout>
Try taking a look at ConstraintLayout.
Though initially a bit intimidating it does everything all the other layouts can do and much more (including what you just asked by using "match_constraint").
It's part of the Support Library as well, so it's usable in older projects.
If I understood you correctly, you want these two Views for the purpose of setting an OnClickListener on them. This is how I would go about it:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/togoTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pickup"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/togoSwitch"
app:layout_constraintTop_toTopOf="parent" />
<com.bhargavms.podslider.PodSlider
android:id="#+id/togoSwitch"
android:layout_width="75dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:numberOfPods="2"
app:selectedPodColor="#color/colorAccent"
app:mainSliderColor="#color/colorPrimary"
app:podColor="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#id/togoTrue"
app:layout_constraintRight_toLeftOf="#id/togoFalse"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/togoFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vor Ort"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#id/togoSwitch"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/togoTrueTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/togoFalseTrigger"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/togoFalseTrigger"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#id/togoTrueTrigger"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

ConstraintLayout chain does not work if some chained views constrained to another chained view

I am not sure whether it is a bug of ConstraintLayout or not, so I try to ask if somebody knows I made any mistake.
I have a layout which I want to spread evenly on the screen 3 elements.
Just like below:
I formed horizontal chains between them and as you can see, they are distributing themselves evenly and working good.
Now I want to place an image plus a TextView centered inside each element, like this:
So this is what I tried to do, taking element 1 as example:
<ImageView
android:id="#+id/image1"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="#drawable/image1"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintLeft_toLeftOf="#id/element_1"
app:layout_constraintTop_toTopOf="#id/element_1"
app:layout_constraintRight_toLeftOf="#+id/text1"
app:layout_constraintHorizontal_chainStyle="packed"/>
<TextView
android:id="#+id/text1"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="2dp"
android:text="#string/text1"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintLeft_toRightOf="#id/image1"
app:layout_constraintRight_toRightOf="#id/element_1"
app:layout_constraintTop_toTopOf="#id/element_1"
app:layout_constraintHorizontal_chainStyle="packed"
android:gravity="center_vertical"/>
Sadly, it seems to "break" the chain of the 3 elements. The 3 elements now does not spread horizontally, but wrapped to a very small size:
If I removed the chain between the ImageView and TextView, it works fine. But then I cannot center the ImageView and TextView inside the element.
Does anyone encountered something like this? How do you solve it?
Now, I know I have at least 2 alternatives to solve this problem:
(1) Use one TextView with a compound drawable, instead of ImageView + TextView;
(2) Use a LinearLayout to wrap the ImageView and TextView
But I want to know why it does not work (So that we can have better understanding of ConstraintLayout), instead of finding an alternative.
Thanks!
After posting my other answer to this question, I realized that it did not address how to center a multi-line TextView.
Referring to the image above, the leftmost box has a single line TextView. The TextView and the ImageView are centered as a group in the the box. This was accomplished by specifying the following for the TextView.
<TextView
android:layout_width="0dp"
app:layout_constraintWidth_default="wrap"
.. the rest of it .../>
See this posting regarding the use of app:layout_constraintWidth_default="wrap".
app:layout_constraintWidth_default="wrap" (with width set to 0dp). If set, the widget will have the same size as if using wrap_content, but will be limited by constraints (i.e. it won't expand beyond them)
Update: It looks like the XML above needs to be changed for ConstraintLayout 1.1.0 beta2. See the release update.
I think what we are now looking for in the XML is the following:
<TextView
android:layout_width="wrap_content"
app:layout_constrainedWidth="true"
.. the rest of it .../>
I have left the rest of this posting using the pre-1.1.0 beta2 layout. To update, just make the changes mentioned above. The centering issue remains.
This works great for the single line example and the views are centered in the box, but we run into difficulty when the TextView spans multiple lines as it does in the middle box of image above. Although the text within the TextView is wrapped and does not expand beyond its constraints, the ImageView and TextView are not centered like we might expect. In fact, the bounds of the TextView extend to the right of the blue box.
My quick fix for this is to insert a zero-width Space widget to the left of the ImageView in the rightmost box. The chain is that box is now anchored between the Space widget and the righthand side of the box. The ImageView is constrained on the left by the Space.
The Space widget can now be expanded to act like a shim to move the ImageView to the right by the amount that will center the chain. (See right box in the image above.) The getExcessWidth() method of MainActivity calculates how wide the Space widget needs to be.
Here is the XML:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="#+id/element_1"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:background="#color/colorPrimary"
app:layout_constraintEnd_toStartOf="#+id/element_2"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/element_2"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:background="#color/colorPrimary"
app:layout_constraintEnd_toStartOf="#+id/element_3"
app:layout_constraintStart_toEndOf="#+id/element_1"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/element_3"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:background="#color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/element_2"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image1"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginLeft="8dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="#id/element_1"
app:layout_constraintRight_toLeftOf="#+id/text1"
app:layout_constraintTop_toTopOf="#id/element_1" />
<ImageView
android:id="#+id/image2"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginLeft="8dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="#id/element_2"
app:layout_constraintRight_toLeftOf="#+id/text2"
app:layout_constraintTop_toTopOf="#id/element_2" />
<android.support.v4.widget.Space
android:id="#+id/spacer3"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="#id/element_3"
app:layout_constraintLeft_toLeftOf="#id/element_3"
app:layout_constraintTop_toTopOf="#id/element_3" />
<ImageView
android:id="#+id/image3"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginLeft="8dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_3"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="#id/spacer3"
app:layout_constraintRight_toLeftOf="#id/text3"
app:layout_constraintTop_toTopOf="#id/element_3" />
<TextView
android:id="#+id/text1"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="8dp"
android:gravity="center_vertical"
android:text="String"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintLeft_toRightOf="#id/image1"
app:layout_constraintRight_toRightOf="#id/element_1"
app:layout_constraintTop_toTopOf="#id/element_1"
app:layout_constraintWidth_default="wrap" />
<TextView
android:id="#+id/text2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="8dp"
android:gravity="center_vertical"
android:text="A 2-line string"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_2"
app:layout_constraintLeft_toRightOf="#id/image2"
app:layout_constraintRight_toRightOf="#id/element_2"
app:layout_constraintTop_toTopOf="#id/element_2"
app:layout_constraintWidth_default="wrap" />
<TextView
android:id="#+id/text3"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginRight="8dp"
android:gravity="center_vertical"
android:text="A 2-line string"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_3"
app:layout_constraintLeft_toRightOf="#id/image3"
app:layout_constraintRight_toRightOf="#id/element_3"
app:layout_constraintTop_toTopOf="#id/element_3"
app:layout_constraintWidth_default="wrap" />
</android.support.constraint.ConstraintLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chained_chains);
ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.constraintLayout);
layout.post(new Runnable() {
#Override
public void run() {
final TextView textView = (TextView) findViewById(R.id.text3);
int excessWidth = getExcessWidth(textView);
if (excessWidth > 0) {
Space spacer = (Space) findViewById(R.id.spacer3);
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) spacer.getLayoutParams();
lp.width = getExcessWidth(textView) / 2;
spacer.setLayoutParams(lp);
}
}
});
}
private int getExcessWidth(TextView textView) {
if (textView.getLineCount() <= 1) {
return 0;
}
Layout layout = textView.getLayout();
int maxWidth = 0;
for (int i = 0; i < textView.getLineCount(); i++) {
maxWidth = Math.max(maxWidth, (int) layout.getLineWidth(i));
}
return Math.max(textView.getWidth() - maxWidth, 0);
}
}
ConstraintLayout appears to be working as expected. You don't specify what kind of view the elements are, so I have taken the TextView and ImageView and chained them inside a View. I also changed the width of the TextView from 0dp (match_constraints) to wrap_content. Here is the result:
..and the XML.
<android.support.constraint.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">
<View
android:id="#+id/element_1"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="#color/colorPrimary"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/element_2"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image1"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="#id/element_1"
app:layout_constraintRight_toLeftOf="#+id/text1"
app:layout_constraintTop_toTopOf="#id/element_1" />
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:gravity="center_vertical"
android:text="A string"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="#id/image1"
app:layout_constraintRight_toRightOf="#id/element_1"
app:layout_constraintTop_toTopOf="#id/element_1" />
<View
android:id="#+id/element_2"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="16dp"
android:background="#color/colorPrimary"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="#+id/element_1"
app:layout_constraintRight_toLeftOf="#+id/element_3"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image2"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="#id/element_2"
app:layout_constraintRight_toLeftOf="#+id/text2"
app:layout_constraintTop_toTopOf="#id/element_2" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:gravity="center_vertical"
android:text="A longer string"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="#id/image2"
app:layout_constraintRight_toRightOf="#id/element_2"
app:layout_constraintTop_toTopOf="#id/element_2" />
<View
android:id="#+id/element_3"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:background="#color/colorPrimary"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="#+id/element_2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image3"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="#mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="#id/element_3"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="#id/element_3"
app:layout_constraintRight_toLeftOf="#+id/text3"
app:layout_constraintTop_toTopOf="#id/element_3" />
<TextView
android:id="#+id/text3"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginLeft="16dp"
android:gravity="center_vertical"
android:text="A still longer string"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#id/element_3"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="#id/image3"
app:layout_constraintRight_toRightOf="#id/element_3"
app:layout_constraintTop_toTopOf="#id/element_3" />
</android.support.constraint.ConstraintLayout>
If this continues to be a problem for you, it would be helpful if you can post more of your XML including the elements. In the meantime, a couple of thoughts.
First, check to make sure that you are not mixing left/right with start/end constraints. If you supply both, they should agree. There has been an inconsistency in how these have been applied by the designer in the past.
Secondly, you can set up barriers to the left and right of each of your elements and chain the TextView and ImageView between these barriers. See this writeup about barriers in ConstraintLayout.
I noticed that you have your inner view chains set to 'packed' with the line
app:layout_constraintHorizontal_chainStyle="packed"
It almost seems like the this functionality is extending out to the parent views (the 'elements in your case').
You should try temporarily removing this line in your markup to see if your problem goes away.
If so, the fix should be easy enough. There are many ways to achieve that same effect without nesting layouts.
This is perhaps the closest you can get to centering the ImageView and TextView in the ConstraintLayout without any kind of Nested layouts.
And here is the code that does that
<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">
<FrameLayout
android:layout_width="0dp"
android:layout_height="110dp"
android:background="#drawable/border_normal"
app:layout_constraintRight_toLeftOf="#+id/frameLayout"
app:layout_constraintLeft_toLeftOf="parent"
android:id="#+id/frameLayout2"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp">
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="110dp"
android:id="#+id/frameLayout"
android:background="#drawable/border_normal"
app:layout_constraintRight_toLeftOf="#+id/frameLayout3"
app:layout_constraintLeft_toRightOf="#+id/frameLayout2"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp">
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="110dp"
app:layout_constraintRight_toRightOf="parent"
android:background="#drawable/border_normal"
app:layout_constraintLeft_toRightOf="#+id/frameLayout"
android:id="#+id/frameLayout3"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp">
</FrameLayout>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="#+id/frameLayout2"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout2"
app:layout_constraintTop_toTopOf="#+id/frameLayout2"
android:layout_marginStart="24dp" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="#+id/frameLayout2"
app:layout_constraintTop_toTopOf="#+id/frameLayout2"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout2"
android:layout_marginRight="16dp"
app:layout_constraintLeft_toRightOf="#+id/imageView"
android:text="TextView"
android:layout_marginEnd="8dp" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="#+id/frameLayout"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout"
app:layout_constraintTop_toTopOf="#+id/frameLayout"
android:layout_marginStart="24dp" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="#+id/frameLayout"
app:layout_constraintTop_toTopOf="#+id/frameLayout"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout"
android:layout_marginRight="16dp"
app:layout_constraintLeft_toRightOf="#+id/imageView2"
android:text="TextView"
android:layout_marginEnd="8dp" />
<ImageView
android:id="#+id/imageView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="#+id/frameLayout3"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout3"
app:layout_constraintTop_toTopOf="#+id/frameLayout3"
android:layout_marginStart="24dp" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="#+id/frameLayout3"
app:layout_constraintTop_toTopOf="#+id/frameLayout3"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout3"
android:layout_marginRight="16dp"
app:layout_constraintLeft_toRightOf="#+id/imageView3"
android:text="TextView"
android:layout_marginEnd="8dp" />
</android.support.constraint.ConstraintLayout>
Alternate Solution
A better solution would be to wrap the Image view and Text view in a ConstraintLayout
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintRight_toRightOf="#+id/frameLayout"
app:layout_constraintLeft_toLeftOf="#+id/frameLayout"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout"
app:layout_constraintTop_toTopOf="#+id/frameLayout"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp">
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toLeftOf="#+id/textView2"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="#+id/imageView2" />
</android.support.constraint.ConstraintLayout>
EDIT
<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:layout_editor_absoluteY="73dp"
tools:layout_editor_absoluteX="0dp">
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="0dp"
android:layout_height="110dp"
android:background="#drawable/border_normal"
app:layout_constraintRight_toLeftOf="#+id/frameLayout3"
app:layout_constraintLeft_toRightOf="#+id/frameLayout2"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp">
</FrameLayout>
<FrameLayout
android:id="#+id/frameLayout3"
android:layout_width="0dp"
android:layout_height="110dp"
android:background="#drawable/border_normal"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="#+id/frameLayout"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp">
</FrameLayout>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round"
app:layout_constraintLeft_toLeftOf="#id/frameLayout2"
app:layout_constraintRight_toLeftOf="#+id/textView2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="#+id/frameLayout2"
app:layout_constraintBottom_toBottomOf="#id/frameLayout2"
android:layout_marginTop="8dp"
android:layout_marginLeft="24dp" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintRight_toRightOf="#id/frameLayout2"
app:layout_constraintLeft_toRightOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/frameLayout2"
app:layout_constraintBottom_toBottomOf="#id/frameLayout2"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp" />
<FrameLayout
android:id="#+id/frameLayout2"
android:layout_width="0dp"
android:layout_height="110dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="#drawable/border_normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/frameLayout"
app:layout_constraintTop_toTopOf="parent">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
The layout will be positioned correctly only if the chain style is set to app:layout_constraintHorizontal_chainStyle="spread_inside"
This is how the output will look like

Categories

Resources