이전엔 버튼의 매개변수별 특징을 알아봤다면 이번엔 Material3에서 제시하는 버튼의 종류에 대해 알아보겠습니다.
버튼 기본 매개변수에 대해 모르신다면 이전 글을 보고 오시는 걸 추천드립니다.
Button 기본
compose의 기본적인 컴포저블 중 하나입니다. 일반적으로 머티리얼3의 컴포저블를 사용하지만 머티리얼의 컴포저블도 Button에 기반을 둔 컴포저블이 많으므로 알아두고 가는게 좋습니다. 속성 modi
huzit.tistory.com
종류

- Elevated button
- Filled button(일반 Button)
- Filled tonal button
- Outlined button
- Text button
- Icon button
- Segmented button
- Floating action button(FAB)
- Extended FAB
각 버튼별 사용 사례
강조 수준 | 요소 | 이론적 해석 | 예시 작업 |
높은 강조 – 화면에서 가장 중요하거나 가장 일반적인 작업
|
Extended FAB | 확장된 FAB의 더 넓은 형식과 텍스트 라벨은 FAB보다 시각적으로 더 눈에 띕니다. FAB가 너무 작아 보이는 대형 화면에서 자주 사용됩니다. |
Compose 만들기 새 스레드 새 파일 |
FAB | FAB는 화면의 기본 작업에 대한 기본 구성 요소로 남아 있습니다. 소형 FAB , FAB 및 대형 FAB 의 세 가지 크기로 제공됩니다 . |
새 컴포즈 생성 | |
Filled Button | 채워진 버튼의 대조적인 표면 색상으로 인해 FAB 다음으로 가장 눈에 띄는 버튼이 됩니다. 흐름의 최종 작업 또는 차단 해제 작업에 사용됩니다. |
저장 확인 완료 |
|
중간 강조 - 다른 화면 요소에 방해가 되지 않는 중요한 작업에 사용됩니다.
|
Filled Tonal Button | 채워진 색조 버튼은 배경색이 더 밝고 레이블 색상이 더 어둡기 때문에 일반 채워진 버튼보다 시각적으로 덜 눈에 띕니다. 흐름에서 최종 작업이나 차단 해제 작업에 여전히 사용되지만 덜 강조됩니다. |
저장 확인 완료 |
Elevation Button | 상승된 버튼은 본질적으로 더 밝은 배경색과 그림자로 채워진 버튼입니다. 그림자 크리프를 방지하려면 버튼이 패턴이 있는 배경과 시각적으로 분리되어야 하는 경우와 같이 꼭 필요한 경우에만 사용하십시오. |
답장 모두 보기 장바구니에 담기 휴지통에서 꺼내기 |
|
Outlined Button | 모두 보기 또는 장바구니에 추가 등 주의가 필요하지만 기본 작업이 아닌 작업에는 윤곽선이 있는 버튼을 사용하세요사용하세요. 이는 누군가에게 마음을 바꾸거나 흐름에서 벗어날 수 있는 기회를 제공하는 데 사용되는 버튼이기도 합니다. |
답장 모두 보기 장바구니에 담기 휴지통에서 꺼내기 |
|
낮은 강조 – 눈에 띄는 정도가 가장 적은 선택 또는 보충 작업에 사용됩니다.
|
Text button | 텍스트 버튼은 시각적으로 덜 눈에 띄므로 대체 옵션과 같이 강조가 낮은 작업에 사용해야 합니다. | 자세히 알아 보기 모두 보기 계정 변경 켜기 |
Segmented button | 분할된 버튼은 단일 아이콘 버튼보다 시각적으로 더 눈에 띕니다. |
왼쪽 정렬 / 중간 정렬 / 오른쪽 정렬
|
|
Icon Button | 가장 컴팩트하고 섬세한 버튼 형태인 아이콘 버튼은 '북마크', '별표' 등 선택적인 보조 동작을 위해 사용됩니다. | 즐겨찾기에 추가 인쇄 |
예제
참고사항으로 각 버튼은 컴포즈의 기본 버튼과 동일하게 내부적으로 Surface를 사용하고 있거나 Box, Button을 사용하고 있으므로 FAB (Floating Action Button)을 제외하고 사용 방법이나 매개변수는 동일합니다.
간단하게 출력되는 결과물과 코드, 내부 코드만 보고 넘어가겠습니다.
Elevated button
Button의 elevation가 기본적으로 할당되어 있는 Material 버튼입니다.

ElevatedButton(onClick = { /*TODO*/ }) {
Text("ElevatedButton")
}
@Composable
fun ElevatedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.elevatedShape,
colors: ButtonColors = ButtonDefaults.elevatedButtonColors(),
elevation: ButtonElevation? = ButtonDefaults.elevatedButtonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) =
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
Filled button (일반 Button)
기본 버튼이라 동일합니다.

Filled tonal button
중간 강조를 위한 Material3 버튼입니다

FilledTonalButton(onClick = { /*TODO*/ }) {
Text("FilledTonalButton")
}
@Composable
fun FilledTonalButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.filledTonalShape,
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
elevation: ButtonElevation? = ButtonDefaults.filledTonalButtonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) =
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
Outlined button
외곽선이 있는 버튼입니다.

OutlinedButton(onClick = { /*TODO*/ }) {
Text(text = "OutlinedButton")
}
@Composable
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.outlinedShape,
colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
elevation: ButtonElevation? = null,
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) =
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
Text button
단일 텍스트 출력을 위한 버튼입니다.

TextButton(onClick = { /*TODO*/ }) {
Text(text = "TextButton")
}
@Composable
fun TextButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.textShape,
colors: ButtonColors = ButtonDefaults.textButtonColors(),
elevation: ButtonElevation? = null,
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.TextButtonContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) =
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
Icon button
아이콘 버튼입니다.

IconButton(onClick = { /*TODO*/ }) {
Icon(painter = painterResource(id = R.drawable.icon_test), contentDescription = "")
}
@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) {
Box(
modifier = modifier
.minimumInteractiveComponentSize()
.size(IconButtonTokens.StateLayerSize)
.clip(IconButtonTokens.StateLayerShape.toShape())
.background(color = colors.containerColor(enabled).value)
.clickable(
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = rememberRipple(
bounded = false,
radius = IconButtonTokens.StateLayerSize / 2
)
),
contentAlignment = Alignment.Center
) {
val contentColor = colors.contentColor(enabled).value
CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
}
}
Filled Icon button

FilledIconButton(onClick = { /*TODO*/ }) {
Icon(painter = painterResource(id = R.drawable.icon_test), contentDescription = "")
}
@Composable
fun FilledIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled).value,
contentColor = colors.contentColor(enabled).value,
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(FilledIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
Floating action button(FAB)
플롯팅 액션 버튼입니다. 주로 추가, 삭제 또는 사용자 메뉴를 보여줄 때 사용합니다.

FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(painter = painterResource(id = R.drawable.icon_test), contentDescription = "")
}
@Composable
fun FloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.shape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit,
) {
Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
shape = shape,
color = containerColor,
contentColor = contentColor,
tonalElevation = elevation.tonalElevation(interactionSource = interactionSource).value,
shadowElevation = elevation.shadowElevation(interactionSource = interactionSource).value,
interactionSource = interactionSource,
) {
CompositionLocalProvider(LocalContentColor provides contentColor) {
// Adding the text style from [ExtendedFloatingActionButton] to all FAB variations. In
// the majority of cases this will have no impact, because icons are expected, but if a
// developer decides to put some short text to emulate an icon, (like "?") then it will
// have the correct styling.
ProvideTextStyle(
MaterialTheme.typography.fromToken(ExtendedFabPrimaryTokens.LabelTextFont),
) {
Box(
modifier = Modifier
.defaultMinSize(
minWidth = FabPrimaryTokens.ContainerWidth,
minHeight = FabPrimaryTokens.ContainerHeight,
),
contentAlignment = Alignment.Center,
) { content() }
}
}
}
}
Extended FAB
자체적으로 Row를 가지고 있어서 여러 content를 넣을 수 있습니다.

ExtendedFloatingActionButton(onClick = { /*TODO*/ }) {
Icon(painter = painterResource(id = R.drawable.icon_test), contentDescription = "")
Spacer(modifier = Modifier.width(10.dp))
Text(text = "FAB")
}
@Composable
fun ExtendedFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.extendedFabShape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit,
) {
FloatingActionButton(
onClick = onClick,
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
) {
Row(
modifier = Modifier
.sizeIn(minWidth = ExtendedFabMinimumWidth)
.padding(horizontal = ExtendedFabTextPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}
}

Segmented button
아직 개발 중이라 바뀌거나 사라질 수 있는 기능입니다.
material3의 버전이 1.2.0 이상이어야 합니다.
SegmentedButton은 두 종류가 있습니다.
- SingleChoiceSegmentedButton
- MultiChoiceSegmentedButton

단일 선택 또는 다중 선택 시 유용한 버튼입니다.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SegmentedButtonSnippets() {
var selectedIndex by remember { mutableStateOf(-1) }
val options = listOf("Day", "Month", "Week")
val checkedList = remember { mutableStateListOf<Int>() }
Column {
SingleChoiceSegmentedButtonRow {
options.forEachIndexed { index, label ->
SegmentedButton(
selected = index == selectedIndex,
onClick = {
if(selectedIndex == index)
selectedIndex = -1
else
selectedIndex = index
},
shape = SegmentedButtonDefaults.itemShape(index = index, count = options.size)
) {
Text(label)
}
}
}
MultiChoiceSegmentedButtonRow {
options.forEachIndexed { index, s ->
SegmentedButton(
checked = index in checkedList,
onCheckedChange = {
if(index in checkedList){
checkedList.remove(index)
} else{
checkedList.add(index)
}
},
shape = SegmentedButtonDefaults.itemShape(index = index, count = options.size)
) {
Text(text = s)
}
}
}
}
}

참고
https://github.com/Huzit/ComposeBlogSample
https://m3.material.io/components/all-buttons
https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary
'안드로이드(Compose) > UI' 카테고리의 다른 글
Button 기본 (0) | 2024.04.16 |
---|---|
[Text] Text 패러미터 정리 (0) | 2023.06.29 |
Preview (0) | 2023.06.27 |