I have a ConstraintLayout
containing a number of elements, including several buttons in a grid layout. Here is a simplified version of the layout (the actual layout includes additional elements):
<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:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 1"
app:layout_constraintBottom_toTopOf="@+id/button3"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 2"
app:layout_constraintBottom_toTopOf="@+id/button4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<Button
android:id="@+id/button3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 3"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintEnd_toStartOf="@+id/button4"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1" />
<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 4"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button3"
app:layout_constraintTop_toBottomOf="@+id/button2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
I want the sizes of the buttons to satisfy two conditions:
In other words, the size of each button should be equal to the size of the largest text of any button. Is it possible to do this in a ConstraintLayout
?
I can satisfy the first condition by setting (as in the above XML) the button widths and heights to odp
and wrap_content
respectively, and this works for the specific case where all the button texts are the same size (as in the above XML, and in the original (English) version of my app), but when they are not (as happens if, eg, Button 4 plus several extra words
is substituted for Button 4
, and as occurs in at least one of the translations of my app), then the button sizes and alignments lose their symmetry and evenness.
I'd like to stick with ConstraintLayout
, preferably without nesting another layout inside it, since this seems to be the recommended way to do things today, but I suppose I can switch if I have to. I've tried some of the ideas from here , but I couldn't get them to work in my case, and as I said, I would really rather stick to a pure ConstraintLayout
if possible.
There are solutions if the buttons are stacked one-over-another or side-by-side such as described here . It is not clear, however, if such solutions expose behaviors that are supported or just the way things happen to fall out with the implementation of ConstraintLayout . In any case, the issue you are facing is how to size all buttons to the widest when they are in a grid.
You will need to make explicit adjustments to the buttons in your layout. You can do this programmatically in your code using a layout change listener .
An alternative is to use a class derived from the ConstraintHelper class that will adjust the button sizes. This class is the basis for some ConstraintLayout widgets such as Barriers . The derived widget can be placed directly into the layout XML.
Here is a sample:
class GreatestWidthHelper @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
override fun updatePostLayout(container: ConstraintLayout) {
var maxWidth = 0
val referencedViews = mutableListOf<View>()
// Find the greatest width of the referenced widgets.
for (i in 0 until this.mCount) {
val id = this.mIds[i]
val view = container.getViewById(id)
if (view.width > maxWidth) {
maxWidth = view.width
}
referencedViews.add(view)
}
// Set the width of all referenced view to the width of the view with the greatest width.
for(view in referencedViews) {
if (view.width != maxWidth) {
view.layoutParams.width = maxWidth
view.requestLayout()
}
}
}
}
I have placed this widget into your XML and made a few other adjustments.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button 1"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/button3"
app:layout_constraintEnd_toStartOf="@+id/centerGuideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button 2"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/button4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/centerGuideline"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button 3"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintEnd_toStartOf="@+id/centerGuideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button 4 Longer"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/centerGuideline"
app:layout_constraintTop_toBottomOf="@+id/button2" />
<com.example.starterapp.GreatestWidthHelper
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="button1,button2,button3,button4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
The widget will be able to make adjustment in the Android Studio designer.
But it will look OK in an emulator.
And will behave if the text of a button is forced to wrap.
The helper class can be further enhanced to take the height of the views into account.
class GreatestSizeHelper @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
override fun updatePostLayout(container: ConstraintLayout) {
var maxWidth = 0
var maxHeight = 0
val referencedViews = mutableListOf<View>()
// Find the greatest width of the referenced widgets.
for (i in 0 until this.mCount) {
val id = this.mIds[i]
val view = container.getViewById(id)
if (view.width > maxWidth) {
maxWidth = view.width
}
if (view.height > maxHeight) {
maxHeight = view.height
}
referencedViews.add(view)
}
// Set the width of all referenced view to the width of the view with the greatest width.
for (view in referencedViews) {
if (view.width != maxWidth || view.height != maxHeight) {
view.layoutParams.width = maxWidth
view.layoutParams.height = maxHeight
view.requestLayout()
}
}
}
}
For want of a better solution, I've decided to just set both the heights and the widths of all the buttons to 0dp
( MATCH_CONSTRAINT
), which allocates all the available space to the buttons and ensures that they'll all be large enough for whatever text appears in them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.