创建小部件的函数和类之间有什么区别?

问题描述 投票:48回答:3

我已经意识到可以使用普通函数创建小部件而不是子类化StatelessWidget。一个例子是这样的:

Widget function({ String title, VoidCallback callback }) {
  return GestureDetector(
    onTap: callback,
    child: // some widget
  );
}

这很有趣,因为它需要的代码远远少于完整的类。例:

class SomeWidget extends StatelessWidget {
  final VoidCallback callback;
  final String title;

  const SomeWidget({Key key, this.callback, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
      return GestureDetector(
        onTap: callback,
        child: // some widget
      );
  }
}

所以我一直在想:除了创建小部件的函数和类之间的语法之外还有什么区别吗?使用函数是一个好习惯吗?

dart flutter
3个回答
78
投票

TL; DR:永远不要使用类上的函数来制作可重用的小部件树。总是将这些提取到StatelessWidget中。


使用函数而不是类之间存在巨大差异,即:框架不知道函数,但可以看到类。

考虑以下“小部件”功能:

Widget functionWidget({ Widget child}) {
  return Container(child: child);
}

用这种方式:

functionWidget(
  child: functionWidget(),
);

它等同于类:

class ClassWidget extends StatelessWidget {
  final Widget child;

  const ClassWidget({Key key, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: child,
    );
  }
}

像那样使用:

new ClassWidget(
  child: new ClassWidget(),
);

在纸面上,两者似乎做了完全相同的事情:创建2个Container,其中一个嵌套到另一个中。但现实略有不同。

在函数的情况下,生成的小部件树如下所示:

Container
  Container

使用类时,窗口小部件树是:

ClassWidget
  Container
    ClassWidget
      Container

这非常重要,因为它从根本上改变了更新窗口小部件时框架的行为方式。以下是差异的精选列表:

  1. 类别: 允许性能优化(const构造函数,operator == override,更精细的重建) 有热重装 被集成到小部件检查器(debugFillProperties) 可以定义键 可以使用上下文API 确保所有小部件以相同的方式使用(始终是构造函数) 确保在两个不同布局之间切换正确处理资源(函数可以重用某些先前的状态)
  2. 功能: 有更少的代码(甚至在那里,我创建了一个代码生成器,使类像函数一样小:functional_widget) ?

结论应该很清楚:

不要使用函数来创建小部件。


3
投票

过去两天我一直在研究这个问题。我得出以下结论:将应用程序的各个部分分解为函数是可以的。这些函数返回StatelessWidget是理想的,因此可以进行优化,例如制作StatelessWidget const,因此如果不需要则不会重建。例如,这段代码完全有效:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      ++_counter;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            const MyWidgetClass(key: const Key('const')),
            MyWidgetClass(key: Key('non-const')),
            _buildSomeWidgets(_counter),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Widget _buildSomeWidgets(int val) {
    print('${DateTime.now()} Rebuild _buildSomeWidgets');
    return const MyWidgetClass(key: Key('function'));

    // This is bad, because it would rebuild this every time
    // return Container(
    //   child: Text("hi"),
    // );
  }
}

class MyWidgetClass extends StatelessWidget {
  const MyWidgetClass({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    print('${DateTime.now()} Rebuild MyWidgetClass $key');

    return Container(
      child: Text("hi"),
    );
  }
}

函数的使用完全没有问题,因为它返回了const StatelessWidget。如果我错了,请纠正我。


-1
投票

当您调用Flutter小部件时,请确保使用const关键字。例如const MyListWidget();

© www.soinside.com 2019 - 2024. All rights reserved.