Skip to main content
Made some refactor and made result more similar to requested
Source Link
Yoloroy
  • 377
  • 2
  • 12

enter image description hereenter image description here

@Preview @Composable fun DoubleButtonPreview() { DoubleButton( text1 = "Smart search", onClick1 = {}, text2 = "Character search", onClick2 = {}, chosenIndex = 0 ) } @Composable fun DoubleButton( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int ) { require(chosenIndex in listOf(0, 1)) val separatorWidthstrokeWidth = 1.5.dp val mainShape = RoundedCornerShape(4.dp) Layout( modifier = Modifier  .border(strokeWidth, Color.Black, mainShape),  content = .border{ DoubleButtonContent(1.dptext1, Color.BlackonClick1, RoundedCornerShape(8.dp)text2, onClick2, chosenIndex, strokeWidth, mainShape) }, contentmeasurePolicy = { measurables, constraints -> TextButtonval (onClickbuttonWidth, buttonHeight) = onClick1calculateButtonsWidthAndHeight(measurables, constraints)   { val placeables = listOf( Textmeasurables[0].measure(text1Constraints.fixed(buttonWidth, buttonHeight)), } measurables[1].measure(Constraints.fixedHeight(buttonHeight)), Box measurables[2].measure(Constraints.fixed(buttonWidth, buttonHeight)) )  modifier = Modifier layout(   width = buttonWidth * 2 + strokeWidth.fillMaxHeightroundToPx(), height = buttonHeight,  .width placementBlock = { placeButtonsAndSeparator(separatorWidthbuttonWidth, placeables) } )  .background(Color.Black} ) }  private fun Placeable.PlacementScope.placeButtonsAndSeparator(  buttonWidth: Int,  placeables: List<Placeable> ) { var start = 0  val TextButton(onClickfirstSpacesWidth = onClick2(buttonWidth - placeables[0].width) {/ 2 val secondSpacesWidth = (buttonWidth - placeables[2].width) / 2  start Text+= firstSpacesWidth placeables[0].place(text2start, 0) start += placeables[0].width + firstSpacesWidth  }placeables[1].place(start, 0) start += placeables[1].width  }, start += secondSpacesWidth placeables[2].place(start, 0) } private fun calculateButtonsWidthAndHeight(  measurePolicy = { measurables, constraints: ->List<Measurable>, constraints: Constraints ): Pair<Int, Int> {  val subButtons = measurables.let { listOf(it[0], it[2]) }   val subButtonsWidths = subButtons.map { it.maxIntrinsicWidth(constraints.maxHeight) }   val maxSubButtonWidth = subButtonsWidths.maxOrNull()!!  val maxSubButtonWidthbuttonHeight = subButtonsWidthssubButtons.maxOrNullfirst()!!.minIntrinsicHeight(maxSubButtonWidth) return Pair(maxSubButtonWidth, buttonHeight) } @Composable private fun DoubleButtonContent(  valtext1: buttonHeightString, =onClick1: subButtons.first().minIntrinsicHeight -> Unit, text2: String, onClick2: (maxSubButtonWidth) -> Unit,  chosenIndex: Int,   strokeWidth: Dp,  mainShape: RoundedCornerShape ) {  val placeablesverticalTextButtonPadding = measurables8.mapdp  { it.measure(Constraints(maxHeight  val horizontalTextButtonPadding = buttonHeight))6.dp  } Box(  modifier = Modifier layout.background( widthcolor = maxSubButtonWidthif *(chosenIndex 2== +0) separatorWidthMaterialTheme.roundToPxcolors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, heightshape = buttonHeightmainShape.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp))   )  ) { Text(  var start  text = 0text1, color = if (chosenIndex val== firstSpacesWidth0) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface,  modifier = Modifier  .onClick(maxSubButtonWidthonClick -= subButtonsWidths[0]onClick1)   / 2  .padding(horizontalTextButtonPadding, verticalTextButtonPadding)  val secondSpacesWidth =  .align(maxSubButtonWidthAlignment.Center)  - subButtonsWidths[1] )   / 2 } Box( modifier = Modifier  start += firstSpacesWidth .fillMaxHeight() .width(strokeWidth)  placeables[0] .placebackground(start,Color.Black)  0 ) Box( modifier = Modifier  start += placeables[0] .widthbackground(  + firstSpacesWidth color = if (chosenIndex == 1) MaterialTheme.colors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, placeables[1]shape = mainShape.placecopy(starttopEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)) )  start) +={  placeables[1] Text( text = text2, color = if (chosenIndex == 1) MaterialTheme.widthcolors.primary else MaterialTheme.colors.onSurface, modifier = Modifier  start += secondSpacesWidth .onClick(onClick = onClick2) placeables[2].placepadding(starthorizontalTextButtonPadding, 0verticalTextButtonPadding) } .align(Alignment.Center) }) )} } 

P.S. When I return, I maybe will make style like in your question

enter image description here

@Preview @Composable fun DoubleButtonPreview() { DoubleButton( text1 = "Smart search", onClick1 = {}, text2 = "Character search", onClick2 = {}, chosenIndex = 0 ) } @Composable fun DoubleButton( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int ) { require(chosenIndex in listOf(0, 1)) val separatorWidth = 1.dp Layout( modifier = Modifier   .border(1.dp, Color.Black, RoundedCornerShape(8.dp)), content = { TextButton(onClick = onClick1) { Text(text1) } Box( modifier = Modifier .fillMaxHeight() .width(separatorWidth) .background(Color.Black) ) TextButton(onClick = onClick2) { Text(text2) } }, measurePolicy = { measurables, constraints -> val subButtons = measurables.let { listOf(it[0], it[2]) }   val subButtonsWidths = subButtons.map { it.maxIntrinsicWidth(constraints.maxHeight) }   val maxSubButtonWidth = subButtonsWidths.maxOrNull()!! val buttonHeight = subButtons.first().minIntrinsicHeight(maxSubButtonWidth) val placeables = measurables.map { it.measure(Constraints(maxHeight = buttonHeight)) } layout( width = maxSubButtonWidth * 2 + separatorWidth.roundToPx(), height = buttonHeight ) { var start = 0 val firstSpacesWidth = (maxSubButtonWidth - subButtonsWidths[0]) / 2  val secondSpacesWidth = (maxSubButtonWidth - subButtonsWidths[1]) / 2 start += firstSpacesWidth placeables[0].place(start, 0) start += placeables[0].width + firstSpacesWidth placeables[1].place(start, 0) start += placeables[1].width start += secondSpacesWidth placeables[2].place(start, 0) } } ) } 

P.S. When I return, I maybe will make style like in your question

enter image description here

@Preview @Composable fun DoubleButtonPreview() { DoubleButton( text1 = "Smart search", onClick1 = {}, text2 = "Character search", onClick2 = {}, chosenIndex = 0 ) } @Composable fun DoubleButton( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int ) { require(chosenIndex in listOf(0, 1)) val strokeWidth = 1.5.dp val mainShape = RoundedCornerShape(4.dp) Layout( modifier = Modifier.border(strokeWidth, Color.Black, mainShape),  content = { DoubleButtonContent(text1, onClick1, text2, onClick2, chosenIndex, strokeWidth, mainShape) }, measurePolicy = { measurables, constraints -> val (buttonWidth, buttonHeight) = calculateButtonsWidthAndHeight(measurables, constraints)    val placeables = listOf( measurables[0].measure(Constraints.fixed(buttonWidth, buttonHeight)),  measurables[1].measure(Constraints.fixedHeight(buttonHeight)),  measurables[2].measure(Constraints.fixed(buttonWidth, buttonHeight)) )   layout(   width = buttonWidth * 2 + strokeWidth.roundToPx(), height = buttonHeight,   placementBlock = { placeButtonsAndSeparator(buttonWidth, placeables) } )  } ) }  private fun Placeable.PlacementScope.placeButtonsAndSeparator(  buttonWidth: Int,  placeables: List<Placeable> ) { var start = 0  val firstSpacesWidth = (buttonWidth - placeables[0].width) / 2 val secondSpacesWidth = (buttonWidth - placeables[2].width) / 2  start += firstSpacesWidth placeables[0].place(start, 0) start += placeables[0].width + firstSpacesWidth  placeables[1].place(start, 0) start += placeables[1].width   start += secondSpacesWidth placeables[2].place(start, 0) } private fun calculateButtonsWidthAndHeight(  measurables: List<Measurable>, constraints: Constraints ): Pair<Int, Int> {  val subButtons = measurables.let { listOf(it[0], it[2]) } val subButtonsWidths = subButtons.map { it.maxIntrinsicWidth(constraints.maxHeight) } val maxSubButtonWidth = subButtonsWidths.maxOrNull()!!  val buttonHeight = subButtons.first().minIntrinsicHeight(maxSubButtonWidth) return Pair(maxSubButtonWidth, buttonHeight) } @Composable private fun DoubleButtonContent(  text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit,  chosenIndex: Int,   strokeWidth: Dp,  mainShape: RoundedCornerShape ) {  val verticalTextButtonPadding = 8.dp    val horizontalTextButtonPadding = 6.dp   Box(  modifier = Modifier .background( color = if (chosenIndex == 0) MaterialTheme.colors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, shape = mainShape.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp))   )  ) { Text(    text = text1, color = if (chosenIndex == 0) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface,  modifier = Modifier  .onClick(onClick = onClick1)   .padding(horizontalTextButtonPadding, verticalTextButtonPadding)    .align(Alignment.Center)   )    } Box( modifier = Modifier   .fillMaxHeight() .width(strokeWidth)   .background(Color.Black)   ) Box( modifier = Modifier   .background(   color = if (chosenIndex == 1) MaterialTheme.colors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, shape = mainShape.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)) )  ) {   Text( text = text2, color = if (chosenIndex == 1) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface, modifier = Modifier   .onClick(onClick = onClick2) .padding(horizontalTextButtonPadding, verticalTextButtonPadding)  .align(Alignment.Center) ) } } 
Source Link
Yoloroy
  • 377
  • 2
  • 12

To get rid of unnecessary recompositions, we need to just move our width calculations into stage of placement of these objects

enter image description here

@Preview @Composable fun DoubleButtonPreview() { DoubleButton( text1 = "Smart search", onClick1 = {}, text2 = "Character search", onClick2 = {}, chosenIndex = 0 ) } @Composable fun DoubleButton( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int ) { require(chosenIndex in listOf(0, 1)) val separatorWidth = 1.dp Layout( modifier = Modifier .border(1.dp, Color.Black, RoundedCornerShape(8.dp)), content = { TextButton(onClick = onClick1) { Text(text1) } Box( modifier = Modifier .fillMaxHeight() .width(separatorWidth) .background(Color.Black) ) TextButton(onClick = onClick2) { Text(text2) } }, measurePolicy = { measurables, constraints -> val subButtons = measurables.let { listOf(it[0], it[2]) } val subButtonsWidths = subButtons.map { it.maxIntrinsicWidth(constraints.maxHeight) } val maxSubButtonWidth = subButtonsWidths.maxOrNull()!! val buttonHeight = subButtons.first().minIntrinsicHeight(maxSubButtonWidth) val placeables = measurables.map { it.measure(Constraints(maxHeight = buttonHeight)) } layout( width = maxSubButtonWidth * 2 + separatorWidth.roundToPx(), height = buttonHeight ) { var start = 0 val firstSpacesWidth = (maxSubButtonWidth - subButtonsWidths[0]) / 2 val secondSpacesWidth = (maxSubButtonWidth - subButtonsWidths[1]) / 2 start += firstSpacesWidth placeables[0].place(start, 0) start += placeables[0].width + firstSpacesWidth placeables[1].place(start, 0) start += placeables[1].width start += secondSpacesWidth placeables[2].place(start, 0) } } ) } 

P.S. When I return, I maybe will make style like in your question