idea中material theme 不生效_在 Flutter 中使用 Theme 统一颜色和字体风格

ff8f32b90f8d2e10e8407f3253e57019.png

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

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

da6aee580e5fb77e1ed82487d7ed3d41.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 查看所有可自定义的颜色和字体样式。

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),
        ),
      ),
    );
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值