Skip to content

Commit abcfc42

Browse files
authored
Support per-platform default typography (flutter#6634)
On Android and Fuchsia, default to Roboto. On iOS, use San Francisco.
1 parent 32c9b4c commit abcfc42

File tree

4 files changed

+120
-11
lines changed

4 files changed

+120
-11
lines changed

packages/flutter/lib/src/material/theme_data.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@ class ThemeData {
122122
indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor;
123123
hintColor ??= isDark ? const Color(0x42FFFFFF) : const Color(0x4C000000);
124124
errorColor ??= Colors.red[700];
125-
textTheme ??= isDark ? Typography.white : Typography.black;
126-
primaryTextTheme ??= primaryIsDark ? Typography.white : Typography.black;
127125
iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
128126
primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
129127
platform ??= defaultTargetPlatform;
128+
129+
final Typography typography = new Typography(platform: platform);
130+
primaryTextTheme ??= primaryIsDark ? typography.white : typography.black;
131+
textTheme ??= isDark ? typography.white : typography.black;
130132
return new ThemeData.raw(
131133
brightness: brightness,
132134
primaryColor: primaryColor,

packages/flutter/lib/src/material/typography.dart

+56-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// found in the LICENSE file.
44

55

6+
import 'package:flutter/foundation.dart';
67
import 'package:flutter/painting.dart';
8+
import 'package:meta/meta.dart';
79

810
import 'colors.dart';
911

@@ -51,7 +53,7 @@ class TextTheme {
5153
this.button
5254
});
5355

54-
const TextTheme._black()
56+
const TextTheme._blackMountainView()
5557
: display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
5658
display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
5759
display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
@@ -64,7 +66,7 @@ class TextTheme {
6466
caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
6567
button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
6668

67-
const TextTheme._white()
69+
const TextTheme._whiteMountainView()
6870
: display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
6971
display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
7072
display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
@@ -77,6 +79,32 @@ class TextTheme {
7779
caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
7880
button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic);
7981

82+
const TextTheme._blackCupertino()
83+
: display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
84+
display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
85+
display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
86+
display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
87+
headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
88+
title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
89+
subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
90+
body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
91+
body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
92+
caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
93+
button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
94+
95+
const TextTheme._whiteCupertino()
96+
: display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
97+
display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
98+
display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
99+
display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
100+
headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
101+
title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
102+
subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
103+
body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
104+
body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
105+
caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
106+
button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic);
107+
80108
/// Extremely large text.
81109
///
82110
/// The font size is 112 pixels.
@@ -255,10 +283,10 @@ class TextTheme {
255283

256284
/// The two material design text themes.
257285
///
258-
/// [Typography.black] and [Typography.white] define the two text themes used in
259-
/// material design. The black text theme, which uses dark glyphs, is used on
260-
/// light backgrounds in light themes. The white text theme, which uses light
261-
/// glyphs, is used in dark themes and on dark backgrounds in in light themes.
286+
/// Material design defines two text themes: [black] and [white]. The black
287+
/// text theme, which uses dark glyphs, is used on light backgrounds in light
288+
/// themes. The white text theme, which uses light glyphs, is used in dark
289+
/// themes and on dark backgrounds in light themes.
262290
///
263291
/// To obtain the current text theme, call [Theme.of] with the current
264292
/// [BuildContext] and read the [ThemeData.textTheme] property.
@@ -269,11 +297,30 @@ class TextTheme {
269297
/// * [ThemeData]
270298
/// * <http://material.google.com/style/typography.html>
271299
class Typography {
272-
Typography._();
300+
/// Creates the default typography for the specified platform.
301+
factory Typography({ @required TargetPlatform platform }) {
302+
assert(platform != null);
303+
switch (platform) {
304+
case TargetPlatform.android:
305+
case TargetPlatform.fuchsia:
306+
return const Typography._(
307+
const TextTheme._blackMountainView(),
308+
const TextTheme._whiteMountainView(),
309+
);
310+
case TargetPlatform.iOS:
311+
return const Typography._(
312+
const TextTheme._blackCupertino(),
313+
const TextTheme._whiteCupertino(),
314+
);
315+
}
316+
return null;
317+
}
318+
319+
const Typography._(this.black, this.white);
273320

274321
/// A material design text theme with dark glyphs.
275-
static const TextTheme black = const TextTheme._black();
322+
final TextTheme black;
276323

277324
/// A material design text theme with light glyphs.
278-
static const TextTheme white = const TextTheme._white();
325+
final TextTheme white;
279326
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
8+
void main() {
9+
test('Defaults to the default typography for the platform', () {
10+
for (TargetPlatform platform in TargetPlatform.values) {
11+
ThemeData theme = new ThemeData(platform: platform);
12+
Typography typography = new Typography(platform: platform);
13+
expect(theme.textTheme, typography.black, reason: 'Not using default typography for $platform');
14+
}
15+
});
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2016 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
8+
void main() {
9+
test('Typography is defined for all target platforms', () {
10+
for (TargetPlatform platform in TargetPlatform.values) {
11+
Typography typography = new Typography(platform: platform);
12+
expect(typography, isNotNull, reason: 'null typography for $platform');
13+
expect(typography.black, isNotNull, reason: 'null black typography for $platform');
14+
expect(typography.white, isNotNull, reason: 'null white typography for $platform');
15+
}
16+
});
17+
18+
test('Typography on Android, Fuchsia defaults to Roboto', () {
19+
expect(new Typography(platform: TargetPlatform.android).black.title.fontFamily, 'Roboto');
20+
expect(new Typography(platform: TargetPlatform.fuchsia).black.title.fontFamily, 'Roboto');
21+
});
22+
23+
test('Typography on iOS defaults to the correct SF font family based on size', () {
24+
// Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
25+
Matcher hasCorrectFont = predicate((TextStyle s) {
26+
return s.fontFamily == (s.fontSize <= 19.0 ? '.SF UI Text' : '.SF UI Display');
27+
}, 'Uses SF Display font for font sizes over 19.0, otherwise SF Text font');
28+
29+
Typography typography = new Typography(platform: TargetPlatform.iOS);
30+
for (TextTheme textTheme in <TextTheme>[typography.black, typography.white]) {
31+
expect(textTheme.display4, hasCorrectFont);
32+
expect(textTheme.display3, hasCorrectFont);
33+
expect(textTheme.display2, hasCorrectFont);
34+
expect(textTheme.display1, hasCorrectFont);
35+
expect(textTheme.headline, hasCorrectFont);
36+
expect(textTheme.title, hasCorrectFont);
37+
expect(textTheme.subhead, hasCorrectFont);
38+
expect(textTheme.body2, hasCorrectFont);
39+
expect(textTheme.body1, hasCorrectFont);
40+
expect(textTheme.caption, hasCorrectFont);
41+
expect(textTheme.button, hasCorrectFont);
42+
}
43+
});
44+
}

0 commit comments

Comments
 (0)