jackpack compose - 스타일 및 테마 설정
지금까지 컴포저블의 스타일을 지정하지 않았지만 어두운 모드 지원을 비롯한 적절한 기본값을 얻었습니다. 이제 BasicsCodelabTheme과 MaterialTheme이 무엇인지 살펴보겠습니다.
ui/theme/Theme.kt 파일을 열면 BasicsCodelabTheme이 구현에서 MaterialTheme을 사용하는 것을 확인할 수 있습니다.
@Composable
fun BasicsCodelabTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
MaterialTheme은 Material 디자인 사양의 스타일 지정 원칙을 반영한 구성 가능한 함수입니다. 스타일 지정 정보는 content의 내부에 있는 구성요소로 하향 적용됩니다. 이러한 구성요소는 이 정보를 읽어 자신의 스타일을 지정합니다. UI에서는 이미 다음과 같이 BasicsCodelabTheme을 사용하고 있습니다.
BasicsCodelabTheme {
MyApp(modifier = Modifier.fillMaxSize())
}
BasicsCodelabTheme은 MaterialTheme을 내부적으로 래핑하므로 MyApp은 테마에 정의된 속성으로 스타일이 지정됩니다. 모든 하위 컴포저블에서 MaterialTheme의 세 가지 속성, colorScheme, typography, shapes를 가져올 수 있습니다. 이러한 속성을 사용하여 Text 중 하나에 헤더 스타일을 설정하세요.
Column(modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding.coerceAtLeast(0.dp))
) {
Text(text = "Hello, ")
Text(text = name, style = MaterialTheme.typography.headlineMedium)
}
위의 예에서 Text 컴포저블은 새 TextStyle을 설정합니다. 고유한 TextStyle을 만들 수도 있고 기본인 MaterialTheme.typography를 사용하여 테마가 정의된 스타일을 가져올 수도 있습니다. 이 구성을 사용하면 Material에 정의된 텍스트 스타일(displayLarge, headlineMedium, titleSmall, bodyLarge, labelMedium 등)에 액세스할 수 있습니다. 이 예제에서는 테마에 정의된 headlineMedium 스타일을 사용합니다.
이제 빌드하여 새롭게 스타일이 지정된 텍스트를 확인합니다.
일반적으로 MaterialTheme 내부의 색상, 모양, 글꼴 스타일을 유지하는 것이 훨씬 좋습니다. 예를 들어, 어두운 모드는 색상을 하드 코딩하는 경우 구현하기 어렵고 오류가 발생하기 쉬운 작업이 많이 요구됩니다.
그러나 가끔 색상과 글꼴 스타일의 선택에서 약간 벗어나야 할 때도 있습니다. 이러한 상황에서는 기존에 사용하고 있는 색상이나 스타일을 기반으로 하는 것이 좋습니다.
이를 위해 copy 함수를 사용하여 미리 정의된 스타일을 수정할 수 있습니다. 다음과 같이 숫자를 더 굵게 만들어 보세요.
Text(
text = name,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold )
)
이런 방법으로 글꼴 모음이나 다른 headlineMedium 속성을 변경해야 하면 작은 편차는 걱정하지 않아도 됩니다.
이제 미리보기 창에 다음과 같은 결과가 표시됩니다.
어두운 모드 미리보기 설정
현재 미리보기에는 밝은 모드에서의 앱 모양만 표시됩니다. DefaultPreview에 UI_MODE_NIGHT_YES와 함께 @Preview 주석을 추가합니다.
@Preview(
showBackground = true,
widthDp = 320,
uiMode = UI_MODE_NIGHT_YES,
name = "Dark"
)
@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreview() {
BasicsCodelabTheme {
Greetings()
}
}
이렇게 하면 어두운 모드의 미리보기가 추가됩니다.
앱 테마 조정
ui/theme 폴더에 있는 파일에서 현재 테마와 관련된 모든 항목을 찾을 수 있습니다. 예를 들어, 지금까지 사용한 기본 색상은 Color.kt에 정의되어 있습니다.
새로운 색상을 정의하는 것부터 시작해 보겠습니다. Color.kt에 다음을 추가합니다.
val Navy = Color(0xFF073042)
val Blue = Color(0xFF4285F4)
val LightBlue = Color(0xFFD7EFFE)
val Chartreuse = Color(0xFFEFF7CF)
이제 Theme.kt에서 MaterialTheme 팔레트에 색상을 할당합니다.
private val LightColorScheme = lightColorScheme(
surface = Blue,
onSurface = Color.White,
primary = LightBlue,
onPrimary = Navy
)
MainActivity.kt로 돌아가서 미리보기를 새로고침해도 미리보기 색상은 실제로 변경되지 않습니다. 미리보기에서 기본적으로 동적 색상이 사용되기 때문입니다. dynamicColor 불리언 매개변수를 사용하여 Theme.kt에서 동적 색상을 추가하는 로직을 확인할 수 있습니다.
색 구성표의 비 적응형 버전을 보려면 API 수준이 31(적응형 색이 도입된 Android S에 해당)보다 낮은 기기에서 앱을 실행하세요. 다음과 같은 새로운 색상이 표시됩니다.
Theme.kt에서 어두운 색상을 위한 팔레트를 정의합니다.
private val DarkColorScheme = darkColorScheme(
surface = Blue,
onSurface = Navy,
primary = Navy,
onPrimary = Chartreuse
)
이제 앱을 실행하면 어두운 색상이 작동하는 것을 확인할 수 있습니다.
Theme.kt의 최종 코드
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.ViewCompat
private val DarkColorScheme = darkColorScheme(
surface = Blue,
onSurface = Navy,
primary = Navy,
onPrimary = Chartreuse
)
private val LightColorScheme = lightColorScheme(
surface = Blue,
onSurface = Color.White,
primary = LightBlue,
onPrimary = Navy
)
@Composable
fun BasicsCodelabTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
(view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}