1 package com.android.permissioncontroller.safetycenter.ui 2 3 import android.content.Context 4 import android.util.AttributeSet 5 import android.view.View.MeasureSpec.EXACTLY 6 import android.widget.LinearLayout 7 import android.widget.Space 8 import androidx.core.view.children 9 10 /** 11 * A [LinearLayout] that requires all its children (except [Space]s) to be the same width. The 12 * layout is horizontal, unless the buttons don't fit in which case it moves to vertical. 13 * 14 * Assumes its children are all WRAP_CONTENT width and that it is some fixed width (either 15 * MATCH_PARENT or sized by constraint - not WRAP_CONTENT itself). 16 */ 17 class EqualWidthContainer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : 18 LinearLayout(context, attrs) { 19 onMeasurenull20 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 21 // super.onMeasure will cause all children to be measured in the default way 22 super.onMeasure(widthMeasureSpec, heightMeasureSpec) 23 24 // Separate children into spaces and non-spaces 25 val (spaces, nonSpaceItems) = children.partition { it is Space } 26 val neededWidthPerNonSpaceItem = 27 try { 28 nonSpaceItems.maxOf { it.measuredWidth } 29 } catch (e: NoSuchElementException) { 30 0 31 } 32 val neededWidth = neededWidthPerNonSpaceItem * nonSpaceItems.count() 33 34 // Switch between horizontal or vertical layout as needed 35 val availableWidth = 36 MeasureSpec.getSize(widthMeasureSpec) - spaces.sumOf { it.measuredWidth } 37 orientation = if (neededWidth <= availableWidth) HORIZONTAL else VERTICAL 38 39 // Measure again now orientation has changed 40 super.onMeasure(widthMeasureSpec, heightMeasureSpec) 41 42 // Re-measure all the children with EXACT width (using previously calculated height) 43 nonSpaceItems.forEach { 44 it.measure( 45 MeasureSpec.makeMeasureSpec(neededWidthPerNonSpaceItem, EXACTLY), 46 MeasureSpec.makeMeasureSpec(it.measuredHeight, EXACTLY) 47 ) 48 } 49 } 50 } 51