Search code examples
androidandroid-jetpack-composeandroid-jetpack-compose-material3

Small OutlinedButton is not aligned to start


My goal is to implement a tiny outlined icon button:

Requirement

However, OutlinedButton is giving me a headache, when the size goes below a certain level, the button starts to stop aligning to the left, akin to having startMargin.

Compose Preview

The question is, how can I align my small button to the start? Appreciate in advance for any helps!

Below is my code:

@Composable
fun ButtonPreview() {
  SetelTheme {
    Surface(
      color = Color.Red.copy(alpha = 0.3f),
      modifier = Modifier.fillMaxWidth(),
    ) {
      Column(
        horizontalAlignment = Alignment.Start,
      ) {
        OutlinedButton(
          onClick = {},
          border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary),
          shape = RoundedCornerShape(4.dp),
          contentPadding = PaddingValues(0.dp),
          modifier = Modifier
            .wrapContentSize()
            .defaultMinSize(
              minWidth = 24.dp,
              minHeight = 24.dp,
            ),
        ) {
          Text("1")
        }

        OutlinedButton(
          onClick = {},
          border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary),
          shape = RoundedCornerShape(4.dp),
          contentPadding = PaddingValues(0.dp),
          modifier = Modifier.wrapContentSize(),
        ) {
          Text("big is ok")
        }
      }
    }
  }
}

Solution

  • Just a hint: You can create CustomButton component like this and modify content color and container color according to your need or you can pass them as arguments:

    @Preview
    @Composable
    fun ButtonPreview() {
        Surface(
            color = Color.Red.copy(alpha = 0.3f),
            modifier = Modifier.fillMaxWidth(),
        ) {
            Column(
                horizontalAlignment = Alignment.Start,
            ) {
                CustomOutlinedButton(
                    onClick = {},
                    border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary),
                    shape = RoundedCornerShape(4.dp),
                    contentPadding = PaddingValues(0.dp),
                    modifier = Modifier
                        .wrapContentSize()
                        .defaultMinSize(
                            minWidth = 24.dp,
                            minHeight = 24.dp,
                        ),
                ) {
                    Text("1")
                }
    
                OutlinedButton(
                    onClick = {},
                    border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary),
                    shape = RoundedCornerShape(4.dp),
                    contentPadding = PaddingValues(0.dp),
                    modifier = Modifier.wrapContentSize(),
                ) {
                    Text("big is ok")
                }
            }
        }
    
    }
    
    
    @Composable
    fun CustomOutlinedButton(
        onClick: () -> Unit,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
        shape: Shape = ButtonDefaults.outlinedShape,
        border: BorderStroke? = ButtonDefaults.outlinedButtonBorder,
        contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
        content: @Composable RowScope.() -> Unit
    ) =
        CustomButton(
            onClick = onClick,
            modifier = modifier,
            enabled = enabled,
            shape = shape,
            border = border,
            contentPadding = contentPadding,
            content = content
        )
    
    
    @Composable
    fun CustomButton(
        onClick: () -> Unit,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
        shape: Shape = ButtonDefaults.shape,
        border: BorderStroke? = null,
        contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
        content: @Composable RowScope.() -> Unit
    ) {
        val containerColor = if (enabled) Color.Blue else Color.Gray
        val contentColor = if (enabled) Color.White else Color.White.copy(0.4f)
        val shadowElevation = 0.dp
        val tonalElevation = 0.dp
    
        Surface(
            modifier = modifier
                .semantics { role = Role.Button }
                .clickable {
                    if (enabled) {
                        onClick()
                    }
                },
            shape = shape,
            color = containerColor,
            contentColor = contentColor,
            tonalElevation = tonalElevation,
            shadowElevation = shadowElevation,
            border = border
        ) {
            CompositionLocalProvider(LocalContentColor provides contentColor) {
                ProvideTextStyle(value = MaterialTheme.typography.labelLarge) {
                    Row(
                        Modifier
                            .padding(contentPadding),
                        horizontalArrangement = Arrangement.Center,
                        verticalAlignment = Alignment.CenterVertically,
                        content = content
                    )
                }
            }
        }
    }