在Flutter中如何覆盖小部件的样式?

6
问题: 我如何自动(如果可能的话)以特定方式样式化我的应用程序中所有 RaisedButton 小部件?
我正在将一个原生Android应用转换成Flutter。在该应用中,所有主要操作按钮都是圆角灰色,并有白色边框。在Android中,只需在styles.xml中定义样式,然后设置<Button style="MyPrimaryButton"/>即可。
而在Flutter中,我只能找到一些例子(包括主题文档中的例子),使用property: Theme.of(context).property来设置单个属性,似乎没有办法传递除颜色和字体之外的样式属性。
以下是我想要用于所有RaisedButton小部件的样式:
RaisedButton(
  color: Theme.of(context).accentColor,
  elevation: 0,
  shape: new RoundedRectangleBorder(
    side: BorderSide(color: Colors.white, width: 1.0, style: BorderStyle.solid),
    borderRadius: new BorderRadius.circular(30)),
)

这个被声称相似的问题被关闭了,原因是主观性太强,但我并没有询问您的意见。我在问是否有一种方法来样式化这些按钮,最好不需要像接受的答案推荐的那样将小部件源代码复制粘贴到我的类中(虽然如果那仍然是唯一的方法,那可能非常好)。


为什么不在MaterialApp主题级别设置按钮主题? - anmol.majhail
我认为我之前对主题化的工作原理不太清楚,但是得益于Hemanth提供的答案,我现在更好地理解了它的使用方法。 - Matt
https://dev59.com/MlQJ5IYBdhLWcg3wlm_B#53533263 - anmol.majhail
谢谢。我在查找重复项时没有看到那个;我的错。 - Matt
2个回答

10

您可以通过扩展RaisedButton类并覆盖需要的默认属性来实现它。

示例:

class Sample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: MyButton(onClicked: () => null,child: Text('Sample'),),
      ),
    );
  }
}

class MyButton extends RaisedButton {
  const MyButton({@required this.onClicked, this.child})
      : super(onPressed: onClicked, elevation: 0.0, child: child);

  final VoidCallback onClicked;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        buttonColor: Theme.of(context).accentColor,
        buttonTheme: Theme.of(context).buttonTheme.copyWith(
              shape: RoundedRectangleBorder(
                side: const BorderSide(
                  color: Colors.white,
                  width: 1.0,
                  style: BorderStyle.solid,
                ),
                borderRadius: BorderRadius.circular(30),
              ),
            ),
      ),
      child: Builder(builder: super.build),
    );
  }
}

无论何时,只要你需要带有自己风格的RaisedButton,使用MyButton即可。

希望这可以帮到你!


啊,好的,我在错误的地方看了。现在试试看。看着这段代码,elevation 被包含在 super 的调用中而不是在 build 方法中与其他属性一起,有什么原因吗?只是好奇。 - Matt
是的,我正在向父类传递属性。这很重要,你可以看到我正在重用父类的“build”方法。 - Hemanth Raj

2
您可以提取已经定制的小部件,然后在任何地方使用它。
这里有三个可能性:
像本地变量、小部件或方法一样使用它。
1- 本地变量 代码:
var raisedButton = RaisedButton(
      color: Theme.of(context).accentColor,
      elevation: 0,
      shape: new RoundedRectangleBorder(
          side: BorderSide(
              color: Colors.white, width: 1.0, style: BorderStyle.solid),
          borderRadius: new BorderRadius.circular(30)),
      onPressed: null,
    );

使用方法:

Container(child: raisedButton),

2-方法

代码:

RaisedButton buildRaisedButton(BuildContext context) {
    return RaisedButton(
          color: Theme.of(context).accentColor,
          elevation: 0,
          shape: new RoundedRectangleBorder(
              side: BorderSide(
                  color: Colors.white, width: 1.0, style: BorderStyle.solid),
              borderRadius: new BorderRadius.circular(30)),
          onPressed: null,
        );
  }

用途:

Container(child: buildRaisedButton(context)),

3- 小部件

代码:

 class MyRaisedButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
            color: Theme.of(context).accentColor,
            elevation: 0,
            shape: new RoundedRectangleBorder(
      side: BorderSide(
          color: Colors.white, width: 1.0, style: BorderStyle.solid),
      borderRadius: new BorderRadius.circular(30)),
            onPressed: null,
          );
  }
}

使用:

Container( child: MyRaisedButton()),

请注意,您可以通过单击小部件并执行(ctrl +)快速完成此操作。
结果将是: enter image description here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接