Material Design은 Google이 제공하는 공식 디자인 시스템으로 최신 버전이 Material3이다.
The latest version, Material 3, enables personal, adaptive, and expressive experiences – from dynamic color and enhanced accessibility, to foundations for large screen layouts and design tokens.
안드로이드 12부터는 Material You를 통해서 개인화된 디자인 시스템을 구성할 수 있다고 한다. 특히
dynamicLightColorScheme()와 dynamicDarkColorScheme()을 통해 구현 가능를 통해서 개인화된 테마도 설정이 가능하다고한다.
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
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
이런식으로 구현되어있는데 회사에서 사용하는 디자인 시스템이 있다면 아마 dynamicColor는 사용될 일이 별로 없을 것이라고 생각된다.
만약 디자인 시스템이 없다면 기능의 하나로 추가해도 괜찮은 차별점으로 할 수 있지 않을까? 라는 생각이 든다.
Material Design은 디자인 토큰으로 구성되어있다고 한다. 이 토큰을 어떤걸 의미하는거고 어느 이점이 있어 사용하는 걸까?
디자인 시스템에서 작고 재사용 가능한 디자인 요소를 뜻한다. 디자인 토큰의 이름은 자기자신을 잘 설명하도록 설정된다.
2가지로 구성되는데
md.ref.palette.secondary90#E8DEF8토큰의 값은 색상, textface, 사이즈값, 다른 토큰값 같은걸 가진다.
예시로는 특정 상태나 브랜드 색상등을 들 수 있다.
브랜드 색상은
primary(토큰) - #E8DEF8(토큰이 나타내는 값)
텍스트 스타일
titleLarge(토큰) - TextStyle(fontSize = 16.sp, .. , fontWeight = FontWeight.Bold)(토큰이 나타내는 값)
primary container color를 #E8DEF8로 설정한 같은 토큰으로 다음 디자이너가 피그마에 디자인을 하고 개발자가 해당 디자인을 구현하면 해당 디자인은 같은 부분에 같은 색상을 넣었다는 일관성을 유지할 수 있다.primary container color의 헥사코드가 변경된다 하더라도 일관적으로 한번에 변경이 가능하다. 개인적으로는 디자인 시스템을 적용한 프로젝트가 개발 시 UI 정확도나 이후의 유지보수가 간편했다.

Theme은 디자인 시스템을 간편하게 도입하고 관리할 수 있도록 도와주는 컴포넌트다. Material3는 안드로이드에서 제공해주는
구성요소로는
로 이루어져있다.
위 세가지 요소들을 CompositionLocal로 전달해서 사용하게 된다. 내부 코드를 보면 staticCompositionLocalOf를 접근할 수 있는 object로 구성되어있는 것을 확인할 수 있다.

ColorScheme도 그렇고 다른 구조들도 미리 정의된 역할들이 있다. 해당 역할에 맞는 색상을 지정해두고 사용하는 방식이다. 각 키워드를 이해하면 색상정의하는데 있어 도움이 될거라고 생각한다.
on 키워드가 붙으면 뒤에 붙은 역할의 text나 icons의 색상더 자세한 내용은 material color문서에서 예시를 보며 이해하는 것이 더 도움이 된다.
UI의 배경의 Radius를 결정
@Immutable
class Shapes(
// Shapes None and Full are omitted as None is a RectangleShape and Full is a CircleShape.
val extraSmall: CornerBasedShape = ShapeDefaults.ExtraSmall,
val small: CornerBasedShape = ShapeDefaults.Small,
val medium: CornerBasedShape = ShapeDefaults.Medium,
val large: CornerBasedShape = ShapeDefaults.Large,
val extraLarge: CornerBasedShape = ShapeDefaults.ExtraLarge,
)
내부를 들여다보면 각 기준에 맞는 RoundedCornerShape를 제공하고 있다.

ColorScheme, Shapes와 비슷하게 TextStyle을 사전에 지정해 각 토큰에 맞는 스타일을 설정해서 사용한다.
어떤 폰트를 사용할건지, 폰트의 weight, size와 자간 및 행간의 조정이 가능하다.
DefaultTextStyle.copy(
fontFamily = TypeScaleTokens.TitleSmallFont, // 폰트 종류
fontWeight = TypeScaleTokens.TitleSmallWeight, // 폰트 weight
fontSize = TypeScaleTokens.TitleSmallSize, // 글자 크기
lineHeight = TypeScaleTokens.TitleSmallLineHeight, // 행간
letterSpacing = TypeScaleTokens.TitleSmallTracking, // 자간
)
내부 코드를 들여다보면 사전 정의된 기본값이 있는걸로 파악할 수 있다.
사내 디자인 시스템의 설정에 맞춰 커스텀을 사용하면 된다.
@Immutable
class Typography(
val displayLarge: TextStyle = TypographyTokens.DisplayLarge,
val displayMedium: TextStyle = TypographyTokens.DisplayMedium,
val displaySmall: TextStyle = TypographyTokens.DisplaySmall,
val headlineLarge: TextStyle = TypographyTokens.HeadlineLarge,
val headlineMedium: TextStyle = TypographyTokens.HeadlineMedium,
val headlineSmall: TextStyle = TypographyTokens.HeadlineSmall,
val titleLarge: TextStyle = TypographyTokens.TitleLarge,
val titleMedium: TextStyle = TypographyTokens.TitleMedium,
val titleSmall: TextStyle = TypographyTokens.TitleSmall,
val bodyLarge: TextStyle = TypographyTokens.BodyLarge,
val bodyMedium: TextStyle = TypographyTokens.BodyMedium,
val bodySmall: TextStyle = TypographyTokens.BodySmall,
val labelLarge: TextStyle = TypographyTokens.LabelLarge,
val labelMedium: TextStyle = TypographyTokens.LabelMedium,
val labelSmall: TextStyle = TypographyTokens.LabelSmall,
)
회사에서 했던 프로젝트에는 디자인시스템의 개발부터 적용까지 담당했는데 Theme을 좀 더 잘 사용했으면 더 쉽고 간편하게 개발 및 유지보수가 가능했을 것이라고 생각한다.
Theme도 결국엔 CompositionLocal을 이용한 기능이니 material이 제공해주는 인터페이스에서 사용하지 않는 값이 많아 복잡성만 늘린다면 직접 관련 클래스와 CompositionLocal을 통해 제공하면 보다 더 관리하기 좋은 디자인 시스템이 될 것이라고 생각한다. 다음 프로젝트에서는 반드시 커스텀을 해보고싶다.
오 좋은 글 감사합니다