
์๋ ํ์ธ์! ์ค๋์ Compose๋ฅผ ์ฌ์ฉํ๋ฉด์ Preview ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ ธ ๊ณ ๋ฏผํ๋ ๊ฒฝํ๊ณผ ์ด๋ฅผ ๊ฐ์ ํ ๋ฐฉ๋ฒ์ ๋ํด ๊ณต์ ํ๋ ค๊ณ ํฉ๋๋ค.
๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ , ํผ๊ทธ๋ง ๋์์ธ์ ์๋ ๋ชจ๋ ๋ฒํผ ์คํ์ผ์ Preview๋ก ํ์ธํ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ค ๋ณด๋ Preview ์ฝ๋๊ฐ ์ ์ ๊ธธ์ด์ง๊ธฐ ์์ํ์ต๋๋ค.
PR์ ์ฌ๋ฆด ๋๋ ๋ฆฌ๋ทฐ์ด๋ถ๋ค๊ป "๋ฒํผ ์ปดํฌ๋ํธ์ Preview๊ฐ ๋ง์ ์ฝ๋๊ฐ ๊ธธ ์ ์๋ค" ๋ ๋ฉ์์ง๋ฅผ ๋จ๊ฒจ์ผ ํ ์ ๋์์ฃ .
ํ์ง๋ง ์ฝ๋ ๋ฆฌ๋ทฐ ์ค ํ ๋ฆฌ๋ทฐ์ด๋ถ๊ป์ PreviewParameter๋ผ๋ ์ ์ฉํ ๊ธฐ๋ฅ์ ์๋ ค์ฃผ์
จ๊ณ , ์ด๋ฅผ ํ์ฉํด ์ฝ๋ ๊ธธ์ด๋ฅผ ํ๊ธฐ์ ์ผ๋ก ์ค์ผ ์ ์์์ต๋๋ค.

Compose์ PreviewParameter๋ Preview๋ฅผ ์ํ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์
๋๋ค. ์ด๋ฅผ ํ์ฉํ๋ฉด ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ๋ค์ํ ์ํ๋ก Previewํ ๋ ๋ฐ๋ณต๋๋ ์ฝ๋๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
์ปดํฌ์ ๋ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ก UI ๋ฏธ๋ฆฌ๋ณด๊ธฐ ย |ย Jetpack Compose ย |ย Android Developers
๋จผ์ , Preview์ ์ฌ์ฉ๋ ๋ฒํผ ์คํ์ผ์ ์ ์ํ๋ PreviewParameterProvider๋ฅผ ์์ฑํฉ๋๋ค.
์ฌ๊ธฐ์ ๊ฐ ๋ฒํผ ์คํ์ผ์ ์ ๊ณตํ๋ ButtonStyleProvider๋ฅผ ์์ฑํ์ด์.
private class ButtonStyleProvider : PreviewParameterProvider<ButtonStyle> {
override val values: Sequence<ButtonStyle> = sequenceOf(
ButtonStyle.Primary,
ButtonStyle.Secondary,
ButtonStyle.Tertiary
)
}
์ ๊ฐ ์์ฑํ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉฐ ์ค๋ช ํ ๊ฒ์!
๋จผ์ , ButtonStyleProvider๋ Preview์ ์ ๋ฌํ ๊ฐ์ ๊ด๋ฆฌํ๋ ํด๋์ค์
๋๋ค. ์ด ํด๋์ค๋ PreviewParameterProvider<T>๋ฅผ ์์๋ฐ์ values ์์ฑ์ ํตํด Preview์์ ์ฌ์ฉํ ๋งค๊ฐ๋ณ์์ ๋ชฉ๋ก์ ์ ๊ณตํฉ๋๋ค.
private class ButtonStyleProvider : PreviewParameterProvider<ButtonStyle> {
override val values: Sequence<ButtonStyle> = sequenceOf(
ButtonStyle.Primary,
ButtonStyle.Secondary,
ButtonStyle.Tertiary
)
}
PreviewParameterProvider<T>: Preview์ ์ ๋ฌํ ๋ฐ์ดํฐ ํ์
T๋ฅผ ๋ช
์ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ButtonStyle ํ์
์ ์ฌ์ฉํฉ๋๋ค.values: Sequence ํ์
์ผ๋ก Preview์์ ์ฌ์ฉํ ์ฌ๋ฌ ๊ฐ์ ์ ์ํฉ๋๋ค.sequenceOf()๋ฅผ ์ฌ์ฉํด ํ์ํ ๋ฒํผ ์คํ์ผ๋ค์ ๋์ดํ์ต๋๋ค.ButtonStyle.Primary, ButtonStyle.Secondary, ButtonStyle.Tertiary ์ธ ๊ฐ์ง ์คํ์ผ์ ์ ๊ณตํฉ๋๋ค.PreviewParameter ์ ๋
ธํ
์ด์
์ฌ์ฉ์ด์ ButtonStyleProvider๋ฅผ ํ์ฉํด Preview ํจ์์์ ๋ค์ํ ์คํ์ผ์ ๋ฏธ๋ฆฌ ๋ณผ ์ ์์ต๋๋ค.
@PreviewParameter ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํด, Preview ํจ์์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ๋ฐ์ ์ ์์ต๋๋ค.
@Preview
@Composable
fun SpoonyButtonEnabledPreview(
@PreviewParameter(ButtonStyleProvider::class) style: ButtonStyle
) {
SpoonyAndroidTheme {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// ์ฌ๊ธฐ์ ์ ๋ฌ๋ฐ์ style์ ์ฌ์ฉ
ButtonSize.entries.forEach { size ->
SpoonyButton(
text = "๋ฒํผ",
style = style, // ์ ๋ฌ๋ฐ์ style
size = size, // ๋ฐ๋ณต๋ฌธ์ผ๋ก ๋ชจ๋ ํฌ๊ธฐ ์ฒ๋ฆฌ
onClick = { }
)
}
}
}
}
style์ ๊ฐ ์ ๋ฌ:@PreviewParameter(ButtonStyleProvider::class)๋ ButtonStyleProvider์์ ์ ์ํ values๋ฅผ ์ํํ๋ฉด์ Preview๋ฅผ ์์ฑํฉ๋๋ค.values์์ ์ ๊ณต๋ ๊ฐ ButtonStyle(Primary, Secondary, Tertiary)์ ๋ํด ๋ณ๋์ Preview ํ๋ฉด์ด ๋ ๋๋ง๋ฉ๋๋ค.ButtonStyle์ ๋ํด ํ ๋ฒ์ฉ Preview๋ฅผ ์์ฑํ์ฌ, ๋์ผํ UI๋ฅผ ๋ค์ํ ์คํ์ผ๋ก ํ์ธํ ์ ์๋๋ก ํฉ๋๋ค.์ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฒํผ ์คํ์ผ(Primary, Secondary, Tertiary) ๊ฐ๊ฐ์ ๋ํด Preview ํ๋ฉด์ด ๋ฐ๋ก ์์ฑ๋ฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก, ์คํ์ผ๋ณ Preview๋ฅผ ์์ฑํ ๋ ์ค๋ณต๋ ์ฝ๋๋ฅผ ์์ฑํ ํ์๊ฐ ์์ด์ง๋๋ค.
๊ธฐ์กด์๋ ๋ฒํผ ์คํ์ผ๊ณผ ํฌ๊ธฐ๋ณ๋ก Preview๋ฅผ ๋ชจ๋ ์์ฑํ๊ธฐ ๋๋ฌธ์ ์ฝ๋๊ฐ ์๋์ฒ๋ผ ๊ธธ์ด์ก์ต๋๋ค.
@Preview
@Composable
private fun SpoonyButtonPrimaryEnabledPreview() {
SpoonyAndroidTheme {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
SpoonyButton(
text = "๋ฒํผ",
onClick = {},
style = ButtonStyle.Primary,
size = ButtonSize.Xlarge
)
SpoonyButton(
text = "๋ฒํผ",
onClick = {},
style = ButtonStyle.Primary,
size = ButtonSize.Large
)
SpoonyButton(
text = "๋ฒํผ",
onClick = {},
style = ButtonStyle.Primary,
size = ButtonSize.Medium
)
SpoonyButton(
text = "๋ฒํผ",
onClick = {},
style = ButtonStyle.Primary,
size = ButtonSize.Small
)
SpoonyButton(
text = "๋ฒํผ",
onClick = {},
style = ButtonStyle.Primary,
size = ButtonSize.Xsmall
)
}
}
}
@Preview
@Composable
private fun SpoonyButtonPrimaryDisabledPreview() {
SpoonyAndroidTheme {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
SpoonyButton(
text = "๋ฒํผ",
style = ButtonStyle.Primary,
size = ButtonSize.Xlarge,
enabled = false
)
SpoonyButton(
text = "๋ฒํผ",
style = ButtonStyle.Primary,
size = ButtonSize.Large,
enabled = false
)
SpoonyButton(
text = "๋ฒํผ",
style = ButtonStyle.Primary,
size = ButtonSize.Medium,
enabled = false
)
SpoonyButton(
text = "๋ฒํผ",
style = ButtonStyle.Primary,
size = ButtonSize.Small,
enabled = false
)
SpoonyButton(
text = "๋ฒํผ",
style = ButtonStyle.Primary,
size = ButtonSize.Xsmall,
enabled = false
)
}
}
}
...
PreviewParameter๋ฅผ ์ฌ์ฉํด ์คํ์ผ์ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ๋ฐ๋๋ก ๊ฐ์ ํ์ต๋๋ค.
๋ฒํผ ํฌ๊ธฐ๋ณ๋ก๋ ๋ฐ๋ณต๋ฌธ์ ํ์ฉํด ์ฝ๋์ ์ค๋ณต์ ์ค์์ด์.
@Preview
@Composable
fun SpoonyButtonEnabledPreview(
@PreviewParameter(ButtonStyleProvider::class) style: ButtonStyle
) {
SpoonyAndroidTheme {
Column(
modifier = Modifier,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
ButtonSize.entries.forEach { size ->
SpoonyButton(
text = "๋ฒํผ",
style = style,
size = size,
onClick = { }
)
}
}
}
}

์์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ ํ๋ Preview๊ฐ ํจ์ฌ ๊ฐ๊ฒฐํด์ก์ต๋๋ค. ๋ฒํผ ์คํ์ผ๊ณผ ํฌ๊ธฐ๋ณ Preview๋ฅผ ํ๋์ ํจ์๋ก ์ฒ๋ฆฌํ ์ ์์ด ์ ์ง๋ณด์๋ ํธ๋ฆฌํด์ก๊ณ , ์ฝ๋ ๊ฐ๋ ์ฑ๋ ํฌ๊ฒ ํฅ์๋์์ฃ .
์ ๋ ํด๋น ๋ฆฌ๋ทฐ๋ฅผ ํตํด PreviewParameter๋ผ๋ ๊ธฐ๋ฅ์ ์๊ฒ ๋ ๊ฒ๋ ํฐ ์ํ์ด์์ต๋๋ค.
Preview๊ฐ ๋๋ฌด ๊ธธ์ด์ ธ ๊ณ ๋ฏผ ์ค์ด๋ผ๋ฉด, ์ ์ฒ๋ผ PreviewParameter๋ฅผ ํ์ฉํด๋ณด๋ ๊ฑด ์ด๋จ๊น์? ์ฝ๋๊ฐ ํจ์ฌ ๊น๋ํด์ง ๊ฑฐ์์! ๐