设计实用教程 | 使用 Theme 统一颜色和字体风格

640?wx_fmt=jpeg

通过定义 Theme,我们可以更好地复用颜色和字体样式,从而让整个 app 的设计看起来更一致。全局 Theme 会在整个 app 范围内生效,而局部 Theme 只作用于特定元素。其实所谓的全局 Theme 和局部 Theme 的区别只在于,全局 Theme 定义在了 app 的 root 处而已。而 MaterialApp 已经事先为你预设了一个全局的 Theme Widget。

在定义一个 Theme 之后,我们可以让它在指定的 widgets (包括 Flutter 自带的 Material widgets,例如 AppBars、Buttons、Checkboxes 等等)中生效。

640?wx_fmt=png

1. 定义一个全局 Theme

全局 Theme 会影响整个 app 的颜色和字体样式。只需要向 MaterialApp 构造器传入 ThemeData 即可。

如果没有放置 Theme,Flutter 将会使用预设的样式。

MaterialApp(
  title: title,
  theme: ThemeData(
    // Define the default brightness and colors.
    brightness: Brightness.dark,
    primaryColor: Colors.lightBlue[800],
    accentColor: Colors.cyan[600],

    // Define the default font family.
    fontFamily: 'Montserrat',

    // Define the default TextTheme. Use this to specify the default
    // text styling for headlines, titles, bodies of text, and more.
    textTheme: TextTheme(
      headline: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold),
      title: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic),
      body1: TextStyle(fontSize: 14.0, fontFamily: 'Hind'),
    ),
  )
);

在 ThemeData 查看所有可自定义的颜色和字体样式。

ThemeData链接:https://api.flutter.dev/flutter/material/ThemeData-class.html

2. 定义一个局部 Theme

如果我们只想对局部进行样式修改,可以创建一个 Theme Widget。

有以下两种方式:定义一个独立的 ThemeData,或者从父级 Theme 扩展。下面为你分别介绍。

2.1 定义一个独立的 ThemeData

如果不想从任何全局 Theme 继承样式,我们可以创建一个 ThemeData() 实例,然后把它传给 Theme widget:

Theme(
  // Create a unique theme with "ThemeData"
  data: ThemeData(
    accentColor: Colors.yellow,
  ),
  child: FloatingActionButton(
    onPressed: () {},
    child: Icon(Icons.add),
  ),
);

2.2 从父级 Theme 扩展

相比从头开始定义一套样式,从父级 Theme 扩展可能更常规一些,使用 copyWith 方法即可。

Theme(
  // Find and extend the parent theme using "copyWith". See the next
  // section for more info on `Theme.of`.
  data: Theme.of(context).copyWith(accentColor: Colors.yellow),
  child: FloatingActionButton(
    onPressed: null,
    child: Icon(Icons.add),
  ),
);

3. 使用定义好的 Theme

现在我们定义好了一个 theme,接下来我们该使用它了!在我们 widget 的 build 方法中调用 Theme.of(context) 函数,可以让这些主题样式生效。

Theme.of(context) 会查询 widget 树,并返回其中最近的 Theme。所以他会优先返回我们之前定义过的一个独立的 Theme,如果找不到,它会返回全局 theme。实际上,FloatingActionButton 就是使用这种方式来定义自己的 accentColor 的。

Container(
  color: Theme.of(context).accentColor,
  child: Text(
    'Text with a background color',
    style: Theme.of(context).textTheme.title,
  ),
);

完整样例

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appName = 'Custom Themes';

    return MaterialApp(
      title: appName,
      theme: ThemeData(
        // Define the default brightness and colors.
        brightness: Brightness.dark,
        primaryColor: Colors.lightBlue[800],
        accentColor: Colors.cyan[600],

        // Define the default font family.
        fontFamily: 'Montserrat',

        // Define the default TextTheme. Use this to specify the default
        // text styling for headlines, titles, bodies of text, and more.
        textTheme: TextTheme(
          headline: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold),
          title: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic),
          body1: TextStyle(fontSize: 14.0, fontFamily: 'Hind'),
        ),
      ),
      home: MyHomePage(
        title: appName,
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({Key key, @required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Container(
          color: Theme.of(context).accentColor,
          child: Text(
            'Text with a background color',
            style: Theme.of(context).textTheme.title,
          ),
        ),
      ),
      floatingActionButton: Theme(
        data: Theme.of(context).copyWith(
          colorScheme:
              Theme.of(context).colorScheme.copyWith(secondary: Colors.yellow),
        ),
        child: FloatingActionButton(
          onPressed: null,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

640?wx_fmt=png

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页