В чем разница между функциями и классами для создания виджетов? - PullRequest
0 голосов
/ 10 ноября 2018

Я понял, что можно создавать виджеты, используя простые функции вместо подклассов 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
      );
  }
}

Так что мне было интересно: есть ли разница, кроме синтаксиса между функциями и классами для создания виджетов?И это хорошая практика для использования функций?

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Когда вы вызываете виджет Flutter, убедитесь, что вы используете ключевое слово const. Например const MyListWidget();

0 голосов
/ 28 апреля 2019

Я изучал эту проблему в течение последних 2 дней. Я пришел к следующему выводу: можно разбивать части приложения на функции. Просто идеально, чтобы эти функции возвращали 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. Пожалуйста, поправьте меня, если я ошибаюсь.

0 голосов
/ 10 ноября 2018

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, оператор == переопределить, более детальная перестройка)
    • есть горячая перезагрузка
    • встроены в инспектор виджетов (debugFillProperties)
    • может определять ключи
    • можно использовать контекстный API
    • убедитесь, что все виджеты используются одинаково (всегда конструктор)
    • гарантирует, что переключение между двумя различными макетами правильно удаляет ресурсы (функции могут повторно использовать некоторое предыдущее состояние)
  2. Функции:

    • имеет меньше кода (и даже там я сделал генератор кода, чтобы сделать классы такими же маленькими, как функции: functions_widget )

Вывод должен быть уже достаточно ясен:

Не используйте функции для создания виджетов .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...