添加了一组新的基本材质按钮小部件和主题 到颤动。原始类已被弃用,将 最终被移除。总体目标是使按钮更多 灵活,更易于通过构造函数参数或 主题。

和 小部件已被 分别替换为 、 和。每个新按钮类都有自己的主题:、 和 。原来的类不再是 使用。按钮的外观由对象指定,而不是一大组小部件参数和 性能。这与外观大致相当 的文本是用对象定义的。新的按钮主题 还配置了一个对象。A 是 本身只是视觉属性的集合。其中许多 属性是用 定义的,这意味着 它们的值可能取决于按钮的状态。FlatButton``RaisedButton``OutlineButton``TextButton``ElevatedButton``OutlinedButton``TextButtonTheme``ElevatedButtonTheme``OutlinedButtonTheme``ButtonTheme``ButtonStyle``TextStyle``ButtonStyle``ButtonStyle``MaterialStateProperty

上下文

而不是尝试发展现有的按钮类及其主题 就地,我们引入了新的替换按钮小部件和 主题。除了将我们从向后兼容性中解放出来之外 就地发展现有类需要的迷宫, 新名称将 Flutter 与材料设计规范同步, 它使用按钮组件的新名称。

旧小部件 旧主题 新建小部件 新主题
FlatButton ButtonTheme TextButton TextButtonTheme
RaisedButton ButtonTheme ElevatedButton ElevatedButtonTheme
OutlineButton ButtonTheme OutlinedButton OutlinedButtonTheme

新主题遵循 Flutter 采用的“标准化”模式 大约一年前的新材质小部件。主题属性和小部件 默认情况下,构造函数参数为 null。非空主题属性 和小部件参数指定组件默认值的覆盖 价值。实现和记录默认值是唯一的 按钮组件小部件的责任。默认值 本身主要基于整体主题的配色方案和 文本主题。

从视觉上看,新按钮看起来有点不同,因为它们匹配 当前的材料设计规范,因为它们的颜色是 根据整体主题的配色方案进行配置。有 填充、圆角半径和 悬停/聚焦/按下反馈。

许多应用程序将能够只替换新的类名 对于旧的。具有最佳配置映像测试或具有其按钮的应用 外观已使用构造函数参数或 原件可能需要查阅迁移指南和 介绍性材料如下。ButtonTheme

API 更改:按钮样式而不是单个样式属性

除了简单的用例,新按钮类的 API 是 与旧类不兼容。新的视觉属性 按钮和主题配置了单个对象, 类似于如何用对象配置 OR 小部件。大多数属性都使用 定义,因此单个属性可以表示 根据按钮的按下/聚焦/悬停/等的不同值 州。ButtonStyle``TextField``Text``TextStyle``ButtonStyle``MaterialStateProperty

按钮不定义按钮的可视属性, 它定义了按钮默认视觉属性的替代, 其中,默认属性由按钮小组件计算 本身。例如,覆盖 的默认前景 (文本/图标)颜色 对于所有状态,可以这样写:ButtonStyle``TextButton

content_copy

TextButton(
  style: ButtonStyle(
    foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
  ),
  onPressed: () { },
  child: Text('TextButton'),
)

这种覆盖很常见;但是,在许多情况下,还有什么 需要覆盖文本按钮使用的叠加颜色 以指示其悬停/聚焦/按下状态。这可以通过以下方式完成 将属性添加到 .overlayColor``ButtonStyle

content_copy

TextButton(
  style: ButtonStyle(
    foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
    overlayColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.hovered))
          return Colors.blue.withOpacity(0.04);
        if (states.contains(MaterialState.focused) ||
            states.contains(MaterialState.pressed))
          return Colors.blue.withOpacity(0.12);
        return null; // Defer to the widget's default.
      },
    ),
  ),
  onPressed: () { },
  child: Text('TextButton')
)

颜色只需要返回一个值 应覆盖其默认值的颜色。如果返回空值,则 将改用小部件的默认值。例如,仅覆盖 文本按钮的焦点叠加颜色:MaterialStateProperty

content_copy

TextButton(
  style: ButtonStyle(
    overlayColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.focused))
          return Colors.red;
        return null; // Defer to the widget's default.
      }
    ),
  ),
  onPressed: () { },
  child: Text('TextButton'),
)

按钮样式实用工具方法styleFrom()

“材质设计”规范定义了按钮的前景色和叠加颜色 配色方案原色的术语。原色为 以不同的不透明度呈现,具体取决于按钮的状态。自 简化创建包含所有属性的按钮样式 取决于配色方案颜色,每个按钮类都包含一个 static styleFrom() 方法,它从一个简单的构造 一组值,包括它所依赖的颜色。ButtonStyle``ColorScheme

本示例创建一个覆盖其前景色的按钮,如 以及其覆盖颜色,使用指定的原色和 材质设计规范中的不透明度。

content_copy

TextButton(
  style: TextButton.styleFrom(
    primary: Colors.blue,
  ),
  onPressed: () { },
  child: Text('TextButton'),
)

文档指示前景色在以下情况下 按钮的禁用基于配色方案的颜色。要覆盖它,请使用 styleFrom():TextButton``onSurface

content_copy

TextButton(
  style: TextButton.styleFrom(
    primary: Colors.blue,
    onSurface: Colors.red,
  ),
  onPressed: null,
  child: Text('TextButton'),
)

如果您尝试创建材料设计,则使用该方法是创建 变化。最灵活的方法是直接定义一个,为以下状态定义值 要覆盖的外观。styleFrom()``ButtonStyle``ButtonStyle``MaterialStateProperty

按钮样式默认值

像新按钮类这样的小部件计算其默认值 基于整体主题和以及 按钮的当前状态。在少数情况下,他们还考虑 整体主题的配色方案是浅色或深色。每个按钮都有一个 根据需要计算其默认样式的受保护方法。虽然 应用程序不会直接调用此方法,其 API 文档解释了所有内容 的默认值是。当按钮或按钮主题指定 时,只有按钮样式的非 null 属性将覆盖 计算的默认值。按钮的参数将覆盖非空值 由相应的按钮主题指定的属性。例如,如果 的样式的属性为非空,则 重写 样式的相同属性。colorScheme``textTheme``ButtonStyle``style``foregroundColor``TextButton``TextButonTheme

如前所述,每个按钮类都包含一个静态方法 调用,它从一组简单的 值,包括它所依赖的颜色。在许多常见的 案例,用于创建一次性的 覆盖默认值,是最简单的。当 自定义样式的目标是覆盖其中一个配色方案 颜色,例如默认样式取决于的颜色 上。对于其他情况,您可以创建一个对象 径直。这样做可以控制视觉对象的值 所有按钮可能状态的属性,如颜色 - 如按下、悬停、禁用和聚焦。styleFrom``ColorScheme``styleFrom``ButtonStyle``primary``onPrimary``ButtonStyle

迁移指南

使用以下信息将按钮迁移到 新的 API。

还原原始按钮视觉对象

在许多情况下,可以从旧的按钮类切换 到新的。这是假设大小/形状的微小变化 颜色可能更大的变化,这不是一个问题。

为了在这些情况下保留原始按钮的外观,可以 定义与原始按钮样式尽可能匹配的按钮样式 喜欢。例如,以下样式使外观 像默认值:TextButton``FlatButton

content_copy

final ButtonStyle flatButtonStyle = TextButton.styleFrom(
  primary: Colors.black87,
  minimumSize: Size(88, 36),
  padding: EdgeInsets.symmetric(horizontal: 16.0),
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(2.0)),
  ),
);

TextButton(
  style: flatButtonStyle,
  onPressed: () { },
  child: Text('Looks like a FlatButton'),
)

同样,要使看起来像默认值:ElevatedButton``RaisedButton

content_copy

final ButtonStyle raisedButtonStyle = ElevatedButton.styleFrom(
  onPrimary: Colors.black87,
  primary: Colors.grey[300],
  minimumSize: Size(88, 36),
  padding: EdgeInsets.symmetric(horizontal: 16),
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(2)),
  ),
);
ElevatedButton(
  style: raisedButtonStyle,
  onPressed: () { },
  child: Text('Looks like a RaisedButton'),
)

的风格多一点 复杂,因为轮廓的颜色更改为原色 按下按钮时。轮廓的外观由 定义,您将使用 a 来定义按下的 轮廓颜色:OutlineButton``OutlinedButton``BorderSide``MaterialStateProperty

content_copy

final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom(
  primary: Colors.black87,
  minimumSize: Size(88, 36),
  padding: EdgeInsets.symmetric(horizontal: 16),
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(2)),
  ),
).copyWith(
  side: MaterialStateProperty.resolveWith<BorderSide>(
    (Set<MaterialState> states) {
      if (states.contains(MaterialState.pressed))
        return BorderSide(
          color: Theme.of(context).colorScheme.primary,
          width: 1,
        );
      return null; // Defer to the widget's default.
    },
  ),
);

OutlinedButton(
  style: outlineButtonStyle,
  onPressed: () { },
  child: Text('Looks like an OutlineButton'),
)

还原整个 应用程序中,您可以在 应用程序的主题:

content_copy

MaterialApp(
  theme: ThemeData.from(colorScheme: ColorScheme.light()).copyWith(
    textButtonTheme: TextButtonThemeData(style: flatButtonStyle),
    elevatedButtonTheme: ElevatedButtonThemeData(style: raisedButtonStyle),
    outlinedButtonTheme: OutlinedButtonThemeData(style: outlineButtonStyle),
  ),
)

还原部分按钮的默认外观 应用程序,您可以使用 、 或 包装小部件子树。例如:TextButtonTheme``ElevatedButtonTheme``OutlinedButtonTheme

content_copy

TextButtonTheme(
  data: TextButtonThemeData(style: flatButtonStyle),
  child: myWidgetSubtree,
)

迁移具有自定义颜色的按钮

以下各节介绍以下 、 和颜色参数的使用:FlatButton``RaisedButton``OutlineButton

content_copy

textColor
disabledTextColor
color
disabledColor
focusColor
hoverColor
highlightColor*
splashColor

新的按钮类不支持单独的突出显示颜色 因为它不再是材料设计的一部分。

迁移具有自定义前景色和背景色的按钮

原始按钮类的两个常见自定义项是自定义项 的前景色或自定义前景色和背景 的颜色。使用新的产生相同的结果 按钮类很简单:FlatButton``RaisedButton

content_copy

FlatButton(
  textColor: Colors.red, // foreground
  onPressed: () { },
  child: Text('FlatButton with custom foreground/background'),
)

TextButton(
  style: TextButton.styleFrom(
    primary: Colors.red, // foreground
  ),
  onPressed: () { },
  child: Text('TextButton with custom foreground'),
)

在这种情况下,前景色(文本/图标)颜色以及 其悬停/聚焦/按下的叠加颜色将基于 .默认情况下,的背景填充颜色为 透明。TextButton``Colors.red``TextButton

使用自定义前景色和背景色迁移 :RaisedButton

content_copy

RaisedButton(
  color: Colors.red, // background
  textColor: Colors.white, // foreground
  onPressed: () { },
  child: Text('RaisedButton with custom foreground/background'),
)

ElevatedButton(
  style: ElevatedButton.styleFrom(
    primary: Colors.red, // background
    onPrimary: Colors.white, // foreground
  ),
  onPressed: () { },
  child: Text('ElevatedButton with custom foreground/background'),
)

在这种情况下,按钮对配色方案原色的使用是 相对于:主要按钮的背景反转 填充颜色,是前景色(文本/图标)颜色。TextButton``onPrimary

使用自定义叠加颜色迁移按钮

覆盖按钮的默认焦点、悬停、突出显示或启动 颜色不太常见。、 和 类具有这些状态相关的单独参数 颜色。新的、 和 类 请改用单个参数。新的 按钮允许为所有 颜色,仅支持原始按钮指定现在的内容 称为“覆盖颜色”。FlatButton``RaisedButton``OutlineButton``TextButton``ElevatedButton``OutlinedButton``MaterialStateProperty

content_copy

FlatButton(
  focusColor: Colors.red,
  hoverColor: Colors.green,
  splashColor: Colors.blue,
  onPressed: () { },
  child: Text('FlatButton with custom overlay colors'),
)

TextButton(
  style: ButtonStyle(
    overlayColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.focused))
          return Colors.red;
        if (states.contains(MaterialState.hovered))
            return Colors.green;
        if (states.contains(MaterialState.pressed))
            return Colors.blue;
        return null; // Defer to the widget's default.
    }),
  ),
  onPressed: () { },
  child: Text('TextButton with custom overlay colors'),
)

新版本更灵活,但不太紧凑。在 原始版本,不同状态的优先级是 隐式(和未记录)和固定的,在新版本中,它是 明确。对于经常指定这些颜色的应用, 最简单的迁移路径是定义一个或多个与上述示例匹配的迁移路径 - 并且仅使用 style 参数 - 或 定义封装三种颜色的无状态包装器小部件 参数。ButtonStyles

迁移具有自定义禁用颜色的按钮

这是一个相对罕见的自定义。、 和 类具有定义背景和前景的参数 当按钮的回调为 null 时的颜色。FlatButton``RaisedButton``OutlineButton``disabledTextColor``disabledColor``onPressed

默认情况下,所有按钮都使用配色方案的颜色, 禁用前景色的不透明度为 0.38。仅具有非透明背景颜色及其默认值 值是不透明度为 0.12 的颜色。所以在很多情况下一个 可以使用该方法覆盖禁用的颜色:onSurface``ElevatedButton``onSurface``styleFrom

content_copy

RaisedButton(
  disabledColor: Colors.red.withOpacity(0.12),
  disabledTextColor: Colors.red.withOpacity(0.38),
  onPressed: null,
  child: Text('RaisedButton with custom disabled colors'),
),

ElevatedButton(
  style: ElevatedButton.styleFrom(onSurface: Colors.red),
  onPressed: null,
  child: Text('ElevatedButton with custom disabled colors'),
)

为了完全控制禁用的颜色,必须明确定义 的样式,如下所示:ElevatedButton``MaterialStateProperties

content_copy

RaisedButton(
  disabledColor: Colors.red,
  disabledTextColor: Colors.blue,
  onPressed: null,
  child: Text('RaisedButton with custom disabled colors'),
)

ElevatedButton(
  style: ButtonStyle(
    backgroundColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.disabled))
          return Colors.red;
        return null; // Defer to the widget's default.
    }),
    foregroundColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.disabled))
          return Colors.blue;
        return null; // Defer to the widget's default.
    }),
  ),
  onPressed: null,
  child: Text('ElevatedButton with custom disabled colors'),
)

与前一种情况一样,有明显的方法可以使新的 在经常出现此迁移的应用程序中版本更紧凑。

使用自定义提升迁移按钮

这也是一种相对罕见的自定义。通常,只有 s(最初称为 ) 包括高程变化。对于成比例的高程 到基线高程(根据材料设计规范), 可以非常简单地覆盖所有这些。ElevatedButton``RaisedButtons

默认情况下,禁用按钮的提升为 0,其余 状态是相对于基线 2 定义的:

content_copy

disabled: 0
hovered or focused: baseline + 2
pressed: baseline + 6

因此,要迁移所有高程都已针对的 定义:RaisedButton

content_copy

RaisedButton(
  elevation: 2,
  focusElevation: 4,
  hoverElevation: 4,
  highlightElevation: 8,
  disabledElevation: 0,
  onPressed: () { },
  child: Text('RaisedButton with custom elevations'),
)

ElevatedButton(
  style: ElevatedButton.styleFrom(elevation: 2),
  onPressed: () { },
  child: Text('ElevatedButton with custom elevations'),
)

任意覆盖一个高程,例如按下 海拔:

content_copy

RaisedButton(
  highlightElevation: 16,
  onPressed: () { },
  child: Text('RaisedButton with a custom elevation'),
)

ElevatedButton(
  style: ButtonStyle(
    elevation: MaterialStateProperty.resolveWith<double?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.pressed))
          return 16;
        return null;
      }),
  ),
  onPressed: () { },
  child: Text('ElevatedButton with a custom elevation'),
)

迁移具有自定义形状和边框的按钮

原始的、 和类全部 提供一个形状参数,用于定义按钮的形状和 其轮廓的外观。相应的新类及其 主题支持指定按钮的形状及其边框 分别,使用 和 参数。FlatButton``RaisedButton``OutlineButton``OutlinedBorder shape``BorderSide side

在此示例中,原始版本指定相同的 边框在其突出显示(按下)状态下的颜色与其他颜色一样 国家。OutlineButton

content_copy

OutlineButton(
  shape: StadiumBorder(),
  highlightedBorderColor: Colors.red,
  borderSide: BorderSide(
    width: 2,
    color: Colors.red
  ),
  onPressed: () { },
  child: Text('OutlineButton with custom shape and border'),
)

OutlinedButton(
  style: OutlinedButton.styleFrom(
    shape: StadiumBorder(),
    side: BorderSide(
      width: 2,
      color: Colors.red
    ),
  ),
  onPressed: () { },
  child: Text('OutlinedButton with custom shape and border'),
)

大多数新小部件的样式参数,包括 它的形状和边框可以用值指定,也就是说,它们可以根据 在按钮的状态上。在以下情况下指定不同的边框颜色 按钮,执行以下操作:OutlinedButton``MaterialStateProperty

content_copy

OutlineButton(
  shape: StadiumBorder(),
  highlightedBorderColor: Colors.blue,
  borderSide: BorderSide(
    width: 2,
    color: Colors.red
  ),
  onPressed: () { },
  child: Text('OutlineButton with custom shape and border'),
)

OutlinedButton(
  style: ButtonStyle(
    shape: MaterialStateProperty.all<OutlinedBorder>(StadiumBorder()),
    side: MaterialStateProperty.resolveWith<BorderSide>(
      (Set<MaterialState> states) {
        final Color color = states.contains(MaterialState.pressed)
          ? Colors.blue
          : Colors.red;
        return BorderSide(color: color, width: 2);
      }
    ),
  ),
  onPressed: () { },
  child: Text('OutlinedButton with custom shape and border'),
)

时间轴

登陆版本:1.20.0-0.0.pre 稳定版本:2.0

引用

接口文档:

相关公关:


原文地址:(https://docs.flutter.dev/release/breaking-changes/buttons#context

发表评论

邮箱地址不会被公开。 必填项已用*标注