Flutter로 아름다운 UI를 구축하다 보면 필연적으로 '테마'라는 거대한 산을 마주하게 됩니다. 앱 전체의 색상, 폰트, 위젯 스타일을 일관성 있게 관리하는 것은 잘 만든 앱의 기본 소양과도 같죠. 특히 색상 시스템을 다룰 때 많은 개발자들이 primaryColor는 직관적으로 이해하지만, primaryColorBrightness라는 속성 앞에서 고개를 갸우뚱하곤 합니다. 단순히 '밝기'라고 생각하기엔 그 동작 방식이 미묘하고, 때로는 예상과 다른 결과를 보여주기 때문입니다. 이 속성이 정확히 무엇이고, 왜 필요하며, Flutter의 핵심 테마 시스템인 ThemeData와 어떻게 유기적으로 연결되는지 깊이 파고들어 보겠습니다.
사실, 풀스택 개발자의 관점에서 보면 primaryColorBrightness는 단순히 UI의 밝기를 조절하는 스위치가 아닙니다. 이것은 '배경색과 전경색의 대비'라는, 접근성과 사용자 경험(UX)의 핵심 원칙을 Flutter 테마 시스템에 녹여낸 철학적인 장치에 가깝습니다. 이 글을 끝까지 읽으신다면, 여러분은 더 이상 AppBar의 아이콘 색상이 왜 하얀색인지, 왜 검은색인지 추측하지 않게 될 것입니다. 대신 명확한 원리를 바탕으로 앱의 색상 시스템을 자유자재로 설계하고 제어할 수 있는 자신감을 얻게 될 것입니다. 또한, 최신 Flutter 버전에서 이 속성이 어떻게 변화하고 있는지, 그리고 앞으로 우리는 어떤 방향으로 나아가야 하는지에 대한 로드맵까지 제시해 드리겠습니다.
핵심 요약: 이 글에서는 primaryColorBrightness의 기본 개념부터 ThemeData 내에서의 역할, 실제 코드 예제를 통한 활용법, 그리고 최신 Flutter에서 권장되는 ColorScheme과의 관계 및 마이그레이션 방법까지, A to Z를 모두 다룹니다. 단순히 속성 하나를 배우는 것을 넘어 Flutter 테마 시스템의 근본적인 동작 원리를 이해하는 계기가 될 것입니다.
1. primaryColorBrightness, 대체 정체가 무엇인가?
가장 기본적인 질문부터 시작해 봅시다. Flutter 공식 문서에서는 primaryColorBrightness를 "The brightness of the primaryColor. Used to determine the color of text and icons placed on top of the primary color."라고 설명합니다. 직역하면 "primaryColor의 밝기. primaryColor 위에 놓이는 텍스트와 아이콘의 색상을 결정하는 데 사용된다"는 뜻입니다.
이 설명에서 핵심은 '위에 놓이는(on top of)'이라는 부분입니다. 즉, primaryColorBrightness는 primaryColor 자체의 색을 바꾸는 속성이 아니라, primaryColor를 배경으로 사용하는 위젯 위의 전경(foreground) 요소들, 예를 들어 AppBar의 제목(title), 아이콘(icons), 상태 표시줄(status bar) 텍스트 등의 색상을 어떻게 보여줄지 결정하는 '가이드라인'입니다.
이 가이드라인에는 두 가지 선택지가 있습니다.
Brightness.dark: "내 배경색(primaryColor)은 어두우니, 그 위에 오는 텍스트나 아이콘은 밝은 색(주로 흰색 계열)으로 보여줘." 라는 의미입니다.Brightness.light: "내 배경색(primaryColor)은 밝으니, 그 위에 오는 텍스트나 아이콘은 어두운 색(주로 검은색 계열)으로 보여줘." 라는 의미입니다.
예를 들어, 우리가 흔히 사용하는 파란색 계열의 primaryColor를 생각해 봅시다. Colors.blue는 상대적으로 어두운 색상에 속합니다. 이 색을 배경으로 사용하는 AppBar 위에 검은색 텍스트가 올라온다면 가독성이 매우 떨어질 것입니다. 따라서 우리는 Flutter에게 "이 파란색은 어두운 계열이야"라고 알려줘야 하고, 이때 primaryColorBrightness: Brightness.dark를 설정하는 것입니다. 그러면 Flutter는 이 정보를 바탕으로 AppBar 위의 텍스트와 아이콘 색상을 자동으로 흰색으로 지정해 줍니다.
// 예시: 어두운 파란색 배경에 맞는 Brightness 설정
ThemeData(
primaryColor: Colors.blue[700], // 상대적으로 어두운 파란색
primaryColorBrightness: Brightness.dark, // 배경이 어두우니 전경은 밝게(흰색)
// ... accentColor 등 다른 속성들
)
반대로, 만약 primaryColor가 아주 밝은 노란색이라면 어떨까요? 이때 primaryColorBrightness: Brightness.light를 설정하면, Flutter는 "아, 배경이 밝구나. 그럼 텍스트는 검은색으로 보여줘야 잘 보이겠네"라고 판단하여 AppBar의 요소들을 검은색으로 렌더링합니다.
// 예시: 밝은 노란색 배경에 맞는 Brightness 설정
ThemeData(
primaryColor: Colors.yellow[200], // 밝은 노란색
primaryColorBrightness: Brightness.light, // 배경이 밝으니 전경은 어둡게(검은색)
// ...
)
중요한 것은
primaryColorBrightness가 색상 값을 직접 지정하는 것이 아니라, '밝다' 또는 '어둡다'라는 시맨틱(semantic)한 정보를 제공한다는 점입니다. Flutter 프레임워크는 이 시맨틱 정보를 해석하여 적절한 대조 색상을 내부적으로 선택합니다. 이 방식은 테마를 더욱 유연하고 추상적으로 관리할 수 있게 해줍니다.
결론적으로, primaryColorBrightness는 개발자가 직접 "파란색 위에는 흰색 텍스트!"라고 하드코딩하는 대신, "이 배경색은 어두운 계열이야"라고 선언적으로 알려줌으로써, 프레임워크가 알아서 적절한 전경색을 선택하게 만드는 우아한 방법인 셈입니다. 이것이 바로 Flutter 테마 시스템이 강력한 이유 중 하나입니다.
2. ThemeData와의 상호작용: 거대한 오케스트라의 지휘자
primaryColorBrightness의 개념을 이해했다면, 이제 이 속성이 Flutter 앱의 디자인 시스템 전체를 관장하는 ThemeData 안에서 어떻게 다른 속성들과 상호작용하는지 알아볼 차례입니다. ThemeData는 수십 개의 속성을 가진 거대한 클래스이며, 이 속성들은 각각 독립적으로 움직이는 것이 아니라 서로 긴밀하게 연결되어 마치 오케스트라처럼 조화롭게 작동합니다. primaryColorBrightness는 이 오케스트라에서 중요한 파트를 연주하는 연주자 중 하나입니다.
ThemeData의 핵심 색상 체계
ThemeData의 색상 시스템을 이해하려면 몇 가지 핵심 속성을 먼저 알아야 합니다.
primaryColor: 앱의 주 색상입니다. 브랜드의 정체성을 나타내며, 주로AppBar, 주요 버튼 등에 사용됩니다.primarySwatch:primaryColor의 단일 색상이 아니라,MaterialColor라는 특정 색상의 음영(shade)들을 모아놓은 집합입니다. 예를 들어Colors.blue는MaterialColor이며,Colors.blue[50]부터Colors.blue[900]까지 다양한 밝기의 파란색을 포함합니다.primaryColor를 직접 지정하는 것보다primarySwatch를 지정하면 Flutter가 내부적으로primaryColor(주로 500 계열),primaryColorDark,primaryColorLight등을 자동으로 설정해줘서 편리합니다.brightness: 앱 전체의 전반적인 밝기 테마를 결정합니다.Brightness.light는 라이트 모드(밝은 배경, 어두운 텍스트),Brightness.dark는 다크 모드(어두운 배경, 밝은 텍스트)를 의미합니다. 이는primaryColorBrightness보다 더 상위의 개념으로, 앱의 기본 배경색(scaffoldBackgroundColor), 카드 색상(cardColor) 등에 영향을 줍니다.accentColor(Deprecated): 보조 색상으로, FloatingActionButton, 활성화된 체크박스 등 사용자의 상호작용을 유도하는 UI 요소에 사용되었습니다. 최신 버전에서는colorScheme.secondary로 대체되었습니다.
primaryColorBrightness는 어떻게 다른 속성에 영향을 미칠까?
primaryColorBrightness는 특히 AppBar와 상태 표시줄(Status Bar)에 가장 직접적인 영향을 미칩니다. AppBar의 배경색은 기본적으로 Theme.of(context).primaryColor를 따라갑니다. 이때 AppBar의 제목, 아이콘, 뒤로가기 버튼 등의 색상은 Theme.of(context).primaryIconTheme.color나 Theme.of(context).textTheme.headline6.color 등을 따라가는데, 이 값들이 바로 primaryColorBrightness에 의해 결정됩니다.
내부적으로 Flutter는 다음과 같은 논리를 따릅니다.
AppBar가 생성될 때, 자신의 배경색으로primaryColor를 사용한다.ThemeData에 설정된primaryColorBrightness를 확인한다.- 만약
Brightness.dark라면, "배경이 어두우니 전경은 밝게"라는 규칙에 따라AppBar의 아이콘 테마(primaryIconTheme)와 텍스트 테마의 색상을Colors.white로 설정한다. - 만약
Brightness.light라면, "배경이 밝으니 전경은 어둡게"라는 규칙에 따라AppBar의 아이콘 테마와 텍스트 테마의 색상을Colors.black으로 설정한다.
여기서 더 나아가, 상태 표시줄의 아이콘/텍스트 색상에도 영향을 줍니다. 안드로이드와 iOS 모두 상단 상태 표시줄(시간, 배터리, 와이파이 아이콘이 있는 영역)의 아이콘 색상을 흰색 또는 검은색으로 제어할 수 있습니다. Flutter의 AppBar는 primaryColorBrightness를 기반으로 이 상태 표시줄의 스타일을 자동으로 설정하려는 시도를 합니다. 이 기능은 SystemUiOverlayStyle과 관련이 깊으며, 뒤에서 더 자세히 다루겠습니다.
실전 예제: 라이트 테마와 다크 테마 만들기
실제 코드를 통해 ThemeData 내에서 primaryColorBrightness가 어떻게 활용되는지 봅시다. 일반적인 앱의 라이트/다크 테마를 정의하는 예제입니다.
import 'package:flutter/material.dart';
// 라이트 테마 정의
final ThemeData lightTheme = ThemeData(
brightness: Brightness.light, // 앱 전체 테마는 라이트
primarySwatch: Colors.teal, // 주 색상 견본은 틸(Teal)
primaryColor: Colors.teal[600], // 주 색상은 약간 어두운 틸
primaryColorBrightness: Brightness.dark, // primaryColor가 어두우므로, 그 위의 전경색은 밝게(흰색)
scaffoldBackgroundColor: Colors.grey[100],
// accentColor는 더 이상 사용되지 않음 -> colorScheme.secondary 사용
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.teal,
brightness: Brightness.light,
).copyWith(secondary: Colors.amber), // 보조 색상은 앰버
textTheme: const TextTheme(
bodyText2: TextStyle(color: Colors.black87),
),
appBarTheme: AppBarTheme(
// AppBarTheme에서 직접 스타일을 지정할 수도 있지만,
// 기본적으로 ThemeData의 색상 설정을 따라감
elevation: 2.0,
),
);
// 다크 테마 정의
final ThemeData darkTheme = ThemeData(
brightness: Brightness.dark, // 앱 전체 테마는 다크
primarySwatch: Colors.blueGrey, // 주 색상 견본은 블루그레이
primaryColor: Colors.blueGrey[800], // 주 색상은 매우 어두운 블루그레이
primaryColorBrightness: Brightness.dark, // primaryColor가 어두우므로, 그 위의 전경색은 밝게(흰색)
scaffoldBackgroundColor: Colors.grey[900],
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.blueGrey,
brightness: Brightness.dark,
).copyWith(secondary: Colors.cyanAccent), // 보조 색상은 사이언 액센트
textTheme: const TextTheme(
bodyText2: TextStyle(color: Colors.white70),
),
appBarTheme: AppBarTheme(
elevation: 2.0,
),
);
// 앱의 진입점
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ThemeData Demo',
// 시스템 설정에 따라 테마를 변경하거나, 직접 선택할 수 있음
theme: lightTheme, // 기본 테마는 라이트 테마
darkTheme: darkTheme, // 다크 모드일 때 사용할 테마
themeMode: ThemeMode.system, // 시스템 설정을 따름
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ThemeData와 Brightness'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'이 텍스트는 기본 텍스트 테마를 따릅니다.',
style: Theme.of(context).textTheme.bodyText2,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: Text('Elevated Button'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
// FAB는 기본적으로 colorScheme.secondary 색상을 사용
),
);
}
}
위 코드에서 lightTheme을 봅시다. primaryColor는 Colors.teal[600]으로, 꽤 어두운 청록색입니다. 따라서 그 위에 흰색 텍스트와 아이콘이 와야 잘 보일 것이므로 primaryColorBrightness: Brightness.dark로 설정했습니다. 만약 이것을 Brightness.light로 잘못 설정하면, AppBar의 텍스트와 아이콘이 검은색으로 표시되어 거의 보이지 않는 '접근성 재앙'이 발생할 것입니다.
이처럼 primaryColorBrightness는 ThemeData라는 복잡한 시스템 속에서 색상 간의 관계와 대비를 정의하는 중요한 역할을 수행합니다. 단순한 밝기 조절이 아니라, 앱의 가독성과 직결되는 핵심 설정인 것입니다.
3. 함정과 해결책: 상태 표시줄(Status Bar) 제어하기
primaryColorBrightness가 자동으로 상태 표시줄 아이콘 색상을 변경해준다고 앞서 언급했지만, 실제 개발 현장에서는 이것이 항상 예상대로 동작하지 않아 많은 개발자들을 혼란에 빠뜨립니다. "분명히 Brightness를 설정했는데 왜 상태 표시줄 아이콘이 그대로지?" 와 같은 문제는 Flutter 커뮤니티의 단골 질문 중 하나입니다.
왜 자동 제어가 실패하는가?
AppBar가 상태 표시줄 스타일을 자동으로 제어하는 기능은 편리하지만, 몇 가지 한계가 있습니다.
Scaffold밖의 영역:AppBar는Scaffold위젯의 일부입니다. 만약AppBar가 없는 화면이거나,AppBar가 화면 전체를 덮지 않는 디자인(예: 투명AppBar)이라면 자동 제어가 제대로 이루어지지 않을 수 있습니다.- 플랫폼별 동작 차이: 안드로이드와 iOS의 상태 표시줄 제어 방식과 기본값이 미묘하게 달라 예기치 않은 결과가 나타날 수 있습니다.
- 다른 위젯의 영향:
AnnotatedRegion과 같은 다른 위젯이 상태 표시줄 스타일을 명시적으로 덮어쓰고 있을 수 있습니다.
이러한 문제를 해결하고 상태 표시줄을 보다 정교하고 안정적으로 제어하기 위해 우리는 SystemUiOverlayStyle을 직접 사용해야 합니다.
SystemUiOverlayStyle을 이용한 명시적 제어
SystemUiOverlayStyle은 상태 표시줄과 네비게이션 바(안드로이드의 하단 버튼 바)의 스타일을 상세하게 정의할 수 있는 클래스입니다. AppBar의 systemOverlayStyle 속성을 통해 이를 직접 설정할 수 있습니다.
주요 속성은 다음과 같습니다.
statusBarColor: 상태 표시줄의 배경색. (주로 투명(Colors.transparent)으로 설정하여AppBar색상이 비치도록 합니다.)statusBarBrightness: (iOS 전용) 상태 표시줄의 전반적인 밝기.Brightness.dark는 어두운 배경/밝은 콘텐츠,Brightness.light는 밝은 배경/어두운 콘텐츠를 의미합니다.statusBarIconBrightness: (안드로이드 전용) 상태 표시줄 아이콘의 밝기.Brightness.dark는 어두운 아이콘(보통 검은색),Brightness.light는 밝은 아이콘(보통 흰색)을 의미합니다.
주의: 여기서 용어가 매우 헷갈립니다! 안드로이드의 statusBarIconBrightness에서 Brightness.dark는 어두운 아이콘을 의미하고, Brightness.light는 밝은 아이콘을 의미합니다. 이는 배경색의 밝기를 기준으로 했던 primaryColorBrightness의 개념과 정반대입니다. 이 차이점을 명확히 인지해야 합니다.
실전 코드: AppBar에서 SystemUiOverlayStyle 사용하기
이제 primaryColorBrightness에만 의존하지 않고, SystemUiOverlayStyle을 통해 상태 표시줄을 명시적으로 제어하는 코드를 작성해 보겠습니다.
// ... 이전 코드에 이어서
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 현재 테마의 primaryColor를 가져옴
final Color primaryColor = Theme.of(context).primaryColor;
// primaryColor의 밝기를 계산 (0.0: 검정, 1.0: 흰색)
final Brightness estimatedBrightness = ThemeData.estimateBrightnessForColor(primaryColor);
// 안드로이드용 상태 표시줄 아이콘 밝기 결정
// 배경이 밝으면(light) 어두운 아이콘(dark), 배경이 어두우면(dark) 밝은 아이콘(light)
final Brightness statusBarIconBrightness =
estimatedBrightness == Brightness.light ? Brightness.dark : Brightness.light;
// iOS용 상태 표시줄 전반적인 밝기 결정 (primaryColorBrightness와 개념이 동일)
final Brightness statusBarBrightness = estimatedBrightness;
return Scaffold(
appBar: AppBar(
title: Text('명시적 상태 표시줄 제어'),
backgroundColor: primaryColor, // 테마의 primaryColor 사용
// systemOverlayStyle을 명시적으로 설정
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // 상태 표시줄 배경은 투명하게
statusBarIconBrightness: statusBarIconBrightness, // Android용 아이콘 밝기
statusBarBrightness: statusBarBrightness, // iOS용 전체 밝기
),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
body: Center(
child: Text('AppBar가 상태 표시줄을 완벽하게 제어합니다.'),
),
);
}
}
위 코드에서는 ThemeData.estimateBrightnessForColor() 헬퍼 함수를 사용하여 primaryColor의 실제 밝기를 계산했습니다. 그리고 그 결과를 바탕으로 안드로이드와 iOS에 맞는 SystemUiOverlayStyle을 생성하여 AppBar에 직접 주입했습니다. 이렇게 하면 primaryColorBrightness 설정에 의존할 때보다 훨씬 더 안정적이고 예측 가능하게 상태 표시줄을 제어할 수 있습니다.
더 나아가, AppBarTheme을 사용하여 앱 전체의 AppBar에 이 스타일을 일괄적으로 적용할 수도 있습니다.
// ThemeData 설정 내부에 추가
appBarTheme: AppBarTheme(
elevation: 2.0,
// 모든 AppBar에 적용될 기본 SystemUiOverlayStyle
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light, // 기본값을 밝은 아이콘(흰색)으로 가정
statusBarBrightness: Brightness.dark, // 기본값을 어두운 배경으로 가정
),
),
이처럼 SystemUiOverlayStyle을 잘 활용하면 primaryColorBrightness의 모호함에서 벗어나, 어떤 상황에서도 디자이너의 의도대로 UI를 구현할 수 있는 강력한 무기를 얻게 됩니다.
4. 현대 Flutter의 흐름: primaryColorBrightness의 종말과 ColorScheme의 부상
지금까지 primaryColorBrightness에 대해 깊이 있게 알아보았지만, 여기서 매우 중요한 사실을 하나 짚고 넘어가야 합니다. 바로 primaryColorBrightness는 최신 Flutter 버전에서 deprecated(사용 자제) 되었다는 것입니다. 물론 당장 사라지지는 않겠지만, Flutter 팀은 더 이상 이 속성을 사용하는 것을 권장하지 않으며, 더 새롭고 강력한 시스템인 ColorScheme으로의 전환을 유도하고 있습니다.
왜 Flutter는 잘 사용되던 이 속성을 버리려고 하는 걸까요? 그 이유는 primaryColorBrightness가 가진 본질적인 한계 때문입니다.
primaryColorBrightness의 한계점
- 제한적인 적용 범위: 이름에서 알 수 있듯이, 이 속성은 오직
primaryColor에만 국한됩니다.accentColor(현secondary)나backgroundColor,errorColor등 다른 색상 위에 올라가는 전경색을 제어할 방법이 없었습니다. 이 때문에 개발자들은 각 색상에 맞는 전경색을 수동으로 결정해야 하는 불편함을 겪었습니다. - 모호함: "밝다", "어둡다"는 개념이 주관적일 수 있으며, 프레임워크가 내부적으로 어떤 색(정확히는
Colors.white또는Colors.black)을 선택하는지 명시적이지 않았습니다. - 확장성 부족: Material Design이 발전하면서 더 다양하고 체계적인 색상 시스템이 요구되었고, 단순히 `primary`와 `accent`만으로는 복잡한 UI의 색상 관계를 표현하기 어려워졌습니다.
대안: 모든 색상에 짝을 지어주는 ColorScheme
이러한 문제들을 해결하기 위해 등장한 것이 바로 ColorScheme입니다. ColorScheme은 Material Design의 색상 시스템을 완벽하게 구현한 클래스로, 단순히 색상 몇 개를 모아놓은 것이 아니라, 모든 배경색에 대해 그에 맞는 전경색(on-color)을 쌍으로 정의하는 훨씬 더 체계적인 접근 방식을 취합니다.
ColorScheme의 주요 속성들을 살펴보면 그 철학을 이해할 수 있습니다.
| 배경색 속성 | 짝이 되는 전경색 속성 ('On-Color') | 설명 |
|---|---|---|
primary |
onPrimary |
주요 색상과 그 위에 표시될 콘텐츠(텍스트, 아이콘)의 색상 |
secondary |
onSecondary |
보조 색상과 그 위에 표시될 콘텐츠의 색상 |
surface |
onSurface |
카드, 다이얼로그 등 표면 색상과 그 위의 콘텐츠 색상 |
background |
onBackground |
앱의 기본 배경색과 그 위의 콘텐츠 색상 |
error |
onError |
오류 표시 색상과 그 위의 콘텐츠 색상 |
보시다시피, ColorScheme은 모든 주요 배경색에 대해 'on' 접두사가 붙은 짝꿍 전경색을 가지고 있습니다. 예를 들어, 여러분이 primary 색상을 어두운 파란색으로 정하면, onPrimary 색상은 자동으로 밝은 흰색 계열로 설정됩니다. 반대로 primary를 밝은 노란색으로 정하면, onPrimary는 어두운 검은색 계열로 설정됩니다. 이것이 바로 primaryColorBrightness가 하던 역할을 훨씬 더 명시적이고 확장 가능한 방식으로 대체하는 것입니다.
ColorScheme으로 ThemeData 마이그레이션하기
이제 primaryColor와 primaryColorBrightness를 사용하던 기존의 ThemeData를 현대적인 ColorScheme 기반으로 바꿔보겠습니다. Flutter는 이를 매우 쉽게 할 수 있도록 ThemeData.from() 생성자와 ColorScheme.fromSeed(), ColorScheme.fromSwatch() 같은 팩토리 메서드를 제공합니다.
기존 방식 (Legacy)
// Legacy ThemeData
final ThemeData legacyLightTheme = ThemeData(
brightness: Brightness.light,
primaryColor: Colors.deepPurple,
primaryColorBrightness: Brightness.dark, // 수동으로 지정
accentColor: Colors.orangeAccent, // Deprecated
);
현대 방식 (Modern)
// Modern ThemeData using ColorScheme
final ThemeData modernLightTheme = ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple, // 씨앗 색상만 지정
brightness: Brightness.light, // 전체 밝기 지정
),
useMaterial3: true, // Material 3 디자인 시스템 사용 권장
);
ColorScheme.fromSeed()를 사용하는 현대적인 방식은 놀랍도록 간결합니다. 우리는 단지 seedColor(씨앗 색상) 하나만 제공했을 뿐인데, Flutter는 이 색상을 기반으로 알고리즘을 통해 조화로운 primary, secondary, tertiary 등 전체 색상 팔레트와 그에 맞는 onPrimary, onSecondary 등을 모두 자동으로 생성해 줍니다. primaryColorBrightness를 고민할 필요조차 없습니다. seedColor가 어두우면 onPrimary는 자동으로 밝아지고, seedColor가 밝으면 onPrimary는 자동으로 어두워집니다.
만약 더 세밀한 제어를 원한다면 ColorScheme 생성자를 직접 사용할 수도 있습니다.
final ThemeData customTheme = ThemeData(
colorScheme: const ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF6200EE),
onPrimary: Colors.white, // 명시적으로 onPrimary 지정
secondary: Color(0xFF03DAC6),
onSecondary: Colors.black, // 명시적으로 onSecondary 지정
error: Color(0xFFB00020),
onError: Colors.white,
background: Color(0xFFFFFFFF),
onBackground: Colors.black,
surface: Color(0xFFFFFFFF),
onSurface: Colors.black,
),
useMaterial3: true,
);
결론적으로,
풀스택 개발자로서의 조언primaryColorBrightness는 Flutter 테마 시스템의 진화 과정에서 나타난 과도기적 속성입니다. 그 원리를 이해하는 것은 Flutter의 동작 방식을 파악하는 데 도움이 되지만, 새로운 프로젝트를 시작하거나 기존 프로젝트를 리팩토링한다면 반드시ColorScheme을 기반으로 테마를 구성해야 합니다. 이것이 바로 Flutter가 지향하는 미래이며, 더 일관성 있고, 확장 가능하며, 유지보수하기 쉬운 코드를 작성하는 길입니다.
5. 결론: 과거를 이해하고 미래로 나아가기
우리는 primaryColorBrightness라는 작은 속성에서 출발하여 Flutter의 테마 시스템, ThemeData의 구조, 상태 표시줄 제어의 복잡성, 그리고 ColorScheme이라는 현대적인 대안에 이르기까지 긴 여정을 함께했습니다.
이 글을 통해 얻어 가야 할 핵심은 다음과 같습니다.
primaryColorBrightness는 배경색(primaryColor)의 밝기를 기준으로 그 위의 전경색(텍스트, 아이콘)을 결정하는 가이드라인이며,Brightness.dark는 '어두운 배경',Brightness.light는 '밝은 배경'을 의미합니다.- 이 속성은
ThemeData내에서AppBar와 상태 표시줄 스타일에 큰 영향을 주지만, 때로는 불안정하게 동작하여SystemUiOverlayStyle을 통한 명시적 제어가 필요할 수 있습니다. primaryColorBrightness는 현재 deprecated 상태이며, Flutter는ColorScheme으로의 전환을 강력히 권장하고 있습니다.ColorScheme은 모든 배경색에 대한 전경색('on-color')을 쌍으로 정의하는 훨씬 더 체계적이고 확장 가능한 시스템입니다.ColorScheme.fromSeed()를 사용하면 씨앗 색상 하나만으로 아름다운 전체 색상 팔레트를 손쉽게 생성할 수 있습니다.
기술은 끊임없이 발전합니다. primaryColorBrightness의 동작 원리를 이해하는 것은 레거시 코드를 유지보수하거나 Flutter 프레임워크의 깊은 곳을 이해하는 데 분명 도움이 됩니다. 하지만 진정한 전문가는 과거의 방식에 머무르지 않고, 더 나은 패러다임을 적극적으로 수용하고 활용하는 사람입니다.
이제 여러분의 Flutter 프로젝트에서 ThemeData를 열어보십시오. 만약 여전히 primaryColorBrightness와 accentColor를 사용하고 있다면, 오늘 배운 내용을 바탕으로 ColorScheme 기반의 현대적인 테마로 리팩토링해 보시는 것은 어떨까요? 그 과정에서 여러분의 앱은 더 견고하고 아름다워질 것이며, 여러분 자신은 한 단계 더 성장한 Flutter 개발자가 되어 있을 것입니다.
다음 단계:
- ColorScheme 공식 문서를 통해 모든 속성을 자세히 살펴보세요.
- Material 3 색상 시스템 가이드를 읽고
primary,secondary,tertiary,surface등의 역할에 대해 더 깊이 이해해 보세요. - 자신의 앱에
ColorScheme.fromSeed()를 적용하여 얼마나 쉽게 아름다운 테마를 만들 수 있는지 직접 경험해 보세요.
Post a Comment