Який зв’язок між віджетами, що містять державний статус, та апаратами без громадянства у Flutter?


104

Віджет із зазначенням стану визначається як будь-який віджет, який змінює свій стан протягом свого життя. Але це дуже поширена практика, коли a StatelessWidgetмає бути StatefulWidgetодним із своїх дітей. Чи не StatelessWidgetстає державним, якщо у нього є StatefulWidgetодна з його дітей?

Я спробував розглянути документацію як частину коду StatelessWidget, але не міг зрозуміти, як StatelessWidgetможе мати Statefulwidgetсвоїх дітей і як і раніше залишатися StatelessWidget.

Яке співвідношення та різниця між віджетами із станом та без громадянства у Flutter?


2
Ви можете скласти свій макет із різних типів віджетів, однак це не означає, що ви успадковуєте характеристики композиції, щоб впливати на кожен віджет. Я маю на увазі, що ви можете мати контейнер без громадянства, який має дочірній інший контейнер, який де-небудь оголошено як StatefulWidget, стан контейнера впливатиме лише на цей один компонент. Отже, вся справа у створенні композиції з різних типів віджетів, кожна функція якої вам потрібна.
aziza

1
Для того, щоб накоїти ще більше, є третій тип віджета: InheritedWidget; Що може зробити StatelessWidgetоновлення.
Rémi Rousselet

Відповіді:


103

StatelessWidget ніколи не буде перебудовувати само по собі (але може від зовнішніх подій). StatefulWidget може. Це золоте правило.

АЛЕ будь-який віджет можна перефарбувати будь-коли.

Без громадянства означає лише те, що всі його властивості незмінні і що єдиним способом їх зміни є створення нового екземпляра цього віджета. Наприклад, це не блокує дерево віджетів.

Але ви не повинні дбати про те, який тип ваших дітей. Це ніяк не впливає на вас.


11
(Порівняно нове в рамках). У чому різниця між rebuildіrepaint
user462455

Крім того, з коментарів у фліртувальному коді фреймворку, мабуть, StateFulWidgets також незмінні.
user462455

3
Побудова віджету - це в основному виклик методу "build" з подальшим створенням / оновленням відповідного візуалізатора; за яким слідує процес фарбування. Що надрукує ці візуалізації на екрані.
Rémi Rousselet

класи, які успадковують "StatefulWidget", є незмінними. Але сам стан (State <YourWidget>) може змінюватися.
Rémi Rousselet

1
@ RémiRousselet Віджети, що містять державу та без громадянства, відновлюють кожен кадр, відповідно до flutter.dev/docs/get-started/flutter-for/…
Мет

82

StatefulWidget проти StatelessWidget.

введіть тут опис зображення

StatelessWidget - віджет, який не потребує змінного стану.

  • Віджет без стану - це віджет, який описує частину користувальницького інтерфейсу, будуючи сузір’я інших віджетів, які описують інтерфейс користувача більш конкретно. Процес побудови триває рекурсивно, поки опис користувальницького інтерфейсу не стане повністю конкретним (наприклад, повністю складається з RenderObjectWidgets, які описують конкретні RenderObjects).

  • statelessВіджет корисний , коли частина призначеного для користувача інтерфейсу ви описуєте не залежить ні від чого, крім інформації про конфігурацію в самому об'єкті і BuildContext , в якому роздутий віджет. Для композицій, які можуть динамічно змінюватися, наприклад через наявність внутрішнього стану, керованого годинником, або залежно від стану системи, розгляньте можливість використання StatefulWidget.

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

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

StatefulWidget - Віджет, що має змінний стан.

  • Віджети, що містять дані, корисні, коли частина описуваного вами інтерфейсу користувача може динамічно змінюватися.

Коли Flutter створює a StatefulWidget, він створює об'єкт State. У цьому об’єкті зберігається весь змінний стан цього віджета.

Поняття держави визначається двома речами:

1) Дані, які використовує віджет, можуть змінюватися.

2) Дані не можна читати синхронно під час побудови віджета. (Усі стани повинні бути встановлені до моменту виклику методу побудови).

Життєвий цикл StategetWidget

Життєвий цикл має такі спрощені кроки:

  1. createState () - Коли Flutter отримує вказівку побудувати StatefulWidget, він негайно викликає createState().
  • Створює змінний стан для цього віджета в певному місці дерева.

  • Підкласи повинні замінити цей метод, щоб повернути новостворений екземпляр пов'язаного з ними підкласу State:

@override
_MyState createState() => _MyState();
  1. mount == true - Усі віджети мають this.mountedвластивість bool . Це стає справжнім, коли buildContextпризначено. Помилкою є дзвінок, setStateколи віджет відключено. Чи цей об’єкт стану наразі знаходиться у дереві.
  • Після створення об'єкта State і перед викликом initStateфреймворк "монтує" об'єкт State, асоціюючи його з
    BuildContext. Об'єкт State залишається змонтованим до
    виклику фреймворку dispose(), після чого фреймворк більше ніколи не буде просити
    об'єкт State будувати знову.

  • Викликати setState є помилкою, якщо не встановлено значення true.

bool get mounted => _element != null;
  1. initState () - це перший метод, який викликається при створенні віджета (звичайно, після конструктора класу).

initStateвикликається один раз і лише один раз. Це повинно дзвонитиsuper.initState().

  • Ініціалізуйте дані, які покладаються на конкретний BuildContext для створеного екземпляра віджета.

  • Ініціалізуйте властивості, які покладаються на ці віджети "батьківські" у дереві.

  • Підпишіться на Streams ChangeNotifiersабо будь-який інший об’єкт, який може змінити дані цього віджета.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
  1. didChangeDependencies () - Викликається, коли змінюється залежність цього об'єкта стану.
  • Цей метод також називається відразу після initState. З BuildContext.inheritFromWidgetOfExactTypeцього методу можна дзвонити безпечно .

  • Підкласи рідко замінюють цей метод, оскільки фреймворк завжди викликає build після змін залежностей. Деякі підкласи перевизначають цей метод, оскільки їм потрібно виконати якусь дорогу роботу (наприклад, мережеві вибірки), коли їх залежності змінюються, і ця робота буде занадто дорогою для кожної збірки.

@protected
@mustCallSuper
void didChangeDependencies() { }
  1. build () - описує частину інтерфейсу користувача, представлену віджетом.

Фреймворк викликає цей метод у ряді різних ситуацій:

  • Після дзвінка initState.
  • Після дзвінка didUpdateWidget.
  • Після отримання дзвінка до setState.
  • Після того, як залежність цього стану об'єкта змінюється (наприклад, InheritedWidget, на який посилається попередня зміна змін).
  • Після виклику деактивуйте, а потім повторно вставте об'єкт стану в дерево в іншому місці.
  • Фреймворк замінює піддерево під цим віджетом на віджет, повернутий цим методом, або шляхом оновлення існуючого піддерева, або шляхом видалення піддерева та роздування нового піддерева, залежно від того, чи може віджет, повернутий цим методом, оновити корінь існуючого піддерева , як визначено за допомогою дзвінка Widget.canUpdate.

  • Зазвичай реалізації повертають новостворену сузір'я віджетів, які налаштовані на інформацію з конструктора цього віджета, заданого BuildContext та внутрішнього стану цього об'єкта стану.

@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }
  1. didUpdateWidget () - Викликається, коли змінюється конфігурація віджета.
  • Якщо батьківський віджет перебудовується і вимагає, щоб це місце в дереві оновилося для відображення нового віджета з тим же типом часу виконання та Widget.key, фреймворк оновить властивість віджета цього об'єкта стану, щоб посилатися на новий віджет, а потім викликати це з попереднім віджетом як аргументом.

  • Перевизначте цей метод, щоб відповісти на зміни віджета (наприклад, для запуску неявних анімацій).

  • Фреймворк завжди викликає build після виклику didUpdateWidget, що означає, що будь-які виклики setState у didUpdateWidget є зайвими.

@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
  1. setState () - Кожного разу, коли ви змінюєте внутрішній стан об'єкта State, вносити зміни у функцію, якій ви передаєте setState:
  • Виклик setState повідомляє структуру про те, що внутрішній стан цього об'єкта змінився таким чином, що може вплинути на користувальницький інтерфейс у цьому піддереві, що змушує структуру планувати побудову для
    цього об'єкта стану.

  • Якщо ви просто змінюєте стан безпосередньо, не викликаючи setState , структура може не запланувати побудову, і користувальницький інтерфейс для цього піддерева може не оновитись , щоб відображати новий стан.

setState(() { _myState = newValue });
  1. деактивувати () - деактивація викликається, коли стан видаляється з дерева, але він може бути повторно вставлений до завершення поточної зміни кадру. Цей метод існує в основному тому, що об'єкти стану можна переміщати з однієї точки дерева в іншу.
  • Фреймворк викликає цей метод щоразу, коли він видаляє цей об'єкт стану з дерева. У деяких випадках фреймворк повторно вставляє об'єкт стану в іншу частину дерева (наприклад, якщо піддерево, що містить цей об'єкт стану, пересаджується з одного місця на дереві в інше). Якщо це станеться, фреймворк забезпечить, щоб він викликав build, щоб дати державному об’єкту можливість адаптуватися до свого нового місця в дереві. Якщо фреймворк знову вставить це піддерево, він зробить це до кінця анімаційного кадру, в якому піддерево було видалено з дерева. З цієї причини державні об'єкти можуть відкласти випуск більшості ресурсів, поки фреймворк не викликає їх метод розпорядження.

Це використовується рідко.

@protected
@mustCallSuper
void deactivate() { }
  1. dispose () - Викликається, коли цей об'єкт назавжди видаляється з дерева.
  • Фреймворк викликає цей метод, коли цей об'єкт стану ніколи більше не будуватиметься. Після викликів фреймворку dispose()об'єкт State вважається немонтованим, а змонтоване властивість хибним. На даний момент викликати setState є помилкою. Цей етап життєвого циклу є кінцевим: немає можливості перемонтувати державний об’єкт, який був утилізований.

  • Підкласи повинні замінити цей метод, щоб звільнити будь-які ресурси, що утримуються цим об’єктом (наприклад, зупинити будь-яку активну анімацію).

@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}

введіть тут опис зображення

Для отримання додаткової інформації перейдіть сюди тут , тут


26

З документації на flutter.io :

... Найголовніше, що тут слід зауважити, в основному віджети без громадянства та державного управління поводяться однаково. Вони відновлюють кожен кадр, різниця полягає в тому, що StatefulWidget має об'єкт стану, який зберігає дані стану у фреймах і відновлює їх.

Якщо ви сумніваєтесь, завжди пам’ятайте це правило: якщо віджет змінюється (наприклад, користувач взаємодіє з ним), він відображається у вигляді стану. Однак, якщо дитина реагує на зміни, батьківський вміст все ще може бути віджетом без громадянства, якщо батько не реагує на зміни.


14

Як згадується у документах до флаттера

У чому справа?

Деякі віджети мають статус держави, а деякі - без громадянства. Якщо віджет змінюється - наприклад, користувач взаємодіє з ним - він відображає стан. Стан віджету складається із значень, які можуть змінюватися, наприклад, поточного значення повзунка або встановленого прапорця. Стан віджета зберігається в об'єкті стану, відокремлюючи стан віджета від його зовнішнього вигляду. Коли стан віджета змінюється, об'єкт стану викликає setState (), повідомляючи фреймворку перекроювати віджет.

Віджет без громадянства не має внутрішнього стану для керування. Icon, IconButton і Text - це приклади віджетів без громадянства, які підкласують StatelessWidget.

З збереженням стану віджета є динамічним. Користувач може взаємодіяти з віджетом, що відображає стан (наприклад, ввівши у форму або перемістивши повзунок, наприклад), або він змінюється з часом (можливо, подача даних призводить до оновлення інтерфейсу). Прапорець, Радіо, Повзунок, InkWell, Форма та TextField - це приклади віджетів, що містять стани, які підкласують StatefulWidget.

https://flutter.io/tutorials/interactive/#stateful-stateless


10

Стан - це інформація, яку (1) можна читати синхронно, коли віджет побудований, і (2) може змінюватися протягом життя віджета. Відповідальність за реалізацію віджетів полягає у забезпеченні негайного повідомлення про стан, коли такий стан змінюється, за допомогою State.setState.

Віджет StatefulWidget :

Віджет із підтримкою стану - це віджет, який описує частину користувальницького інтерфейсу, будуючи сузір’я інших віджетів, які конкретніше описують користувальницький інтерфейс. Процес побудови триває рекурсивно, поки опис користувальницького інтерфейсу не стане повністю конкретним (наприклад, повністю складається з RenderObjectWidgets, які описують конкретні RenderObjects).

Віджет, що містить дані про стан, корисний, коли частина описуваного вами користувача інтерфейсу може змінюватися динамічно, наприклад, через наявність внутрішнього стану, керованого тактовою частотою, або залежно від стану системи. Для композицій, які залежать лише від інформації про конфігурацію в самому об’єкті та BuildContext, в якому віджет надутий, рекомендується використовувати StatelessWidget.

Самі екземпляри StatefulWidget є незмінними і зберігають свій змінний стан або в окремих об'єктах стану, створених методом createState, або в об'єктах, на які цей штат підписаний, наприклад об'єкти Stream або ChangeNotifier, посилання на які зберігаються у кінцевих полях StatefulWidget себе.

Віджет без громадянства :

Віджет без стану - це віджет, який описує частину користувальницького інтерфейсу, будуючи сузір’я інших віджетів, які описують інтерфейс користувача більш конкретно. Процес побудови триває рекурсивно, поки опис користувальницького інтерфейсу не стане повністю конкретним (наприклад, повністю складається з RenderObjectWidgets, які описують конкретні RenderObjects).

Віджет без стану може бути корисним, коли частина описуваного вами користувацького інтерфейсу не залежить ні від чого іншого, крім інформації про конфігурацію в самому об'єкті та BuildContext, в якому віджет надувається. Для композицій, які можуть динамічно змінюватися, наприклад через наявність внутрішнього стану, керованого тактовою частотою, або залежно від стану системи, розгляньте можливість використання StatefulWidget.


9

Віджети без громадянства - це статичні віджети. Вам потрібно просто передати кілька властивостей перед ініціалізацією віджетів без громадянства. Вони не залежать від будь-яких змін даних або будь-якої зміни поведінки. Наприклад. Текст, піктограма, піднята кнопка - це віджети без громадянства.

Віджети, що містять статус, - це динамічні віджети, які можна оновлювати під час виконання на основі дії користувача або зміни даних. Якщо віджет може змінити свій стан під час роботи, він буде віджетом.

Редагувати 15/11/2018

Віджети без стану можуть повторно відтворювати, якщо вхідні / зовнішні дані змінилися (зовнішні дані - це дані, які передаються через конструктор). Оскільки віджети без громадянства не мають стану, вони відображатимуться один раз і не оновлюватимуться самі, а будуть оновлюватися лише при зміні зовнішніх даних.

Тоді як віджети Stateful мають внутрішній стан і можуть повторно відображати їх у разі зміни вхідних даних або зміни стану віджета.

Як віджети без громадянства, так і відмінні від статі мають різний життєвий цикл.


Навіть після передачі нових даних ззовні у Statelessвіджет, ми можемо змінити їх також під час роботи, але вони не називаються Statefulвіджетами (на відміну від вашого останнього рядка).
CopsOnRoad

Чи можете ви пояснити, як віджет без громадянства можна "оновлювати при зміні зовнішніх даних"? (З "зовнішніми даними є дані, які передаються через конструктор".) Чи не буде конструктор викликаний лише один раз? Як змінюються дані, передані через конструктор?
user1596274

8

Я можу придумати дуже просту аналогію. У вас є якийсь предмет меблів із книгами, прикрасами та телевізором. Меблі без громадянства, вони нічого не рухають. У телевізорі, з іншого боку, ви можете увімкнути, вимкнути, змінити канал, відтворити фільм, якщо до нього прикріплений якийсь DVD тощо. Телевізор має внутрішній стан, який впливає на поведінку. У меблях у вас немає держави. Наявність телевізора в меблях не додає йому стану. Сподіваюся, це допомагає.


Це не відповідає на конкретне запитання автора.
Ісая

1
Це чудова аналогія!
Вільям Террілл,

6

Відповідь на запитання щодо переповнення стека - державність проти безгромадянства .

У Flutter відмінність полягає в тому, що віджети без стану можуть визначатися лише усіма аргументами конструктора. Якщо ви створите два віджети без громадянства, використовуючи однакові аргументи, вони будуть однаковими.

Однак віджет із статусом не обов’язково збігається з іншим, побудованим з тими ж аргументами конструктора. Це може бути в іншому стані.
Насправді віджет із станом само по собі є незмінним (без стану), але Flutter управляє окремим об'єктом стану та асоціює його з віджетом, як пояснюється в документі StatefulWidget . Це означає, що коли Flutter відновлює віджет, що містить статус, він перевірить, чи слід повторно використовувати попередній об’єкт стану, і, за бажанням, приєднає цей об’єкт стану до віджету.

Батьківський віджет без громадянства, оскільки він не піклується про стан своєї дитини. Дитяча держава сама (або технічно Флаттер) подбає про свій стан.
На високому рівні, я погоджуюсь, що це робить батьківський віджет державним, оскільки два батьки можуть містити двох дітей з різними станами і, отже, самі технічно відрізнятися. Але з точки зору Флаттера, він будує батьківський віджет, не дбаючи про стан, і лише при побудові дитина враховуватиме його стан.


5

Що таке віджети Stateful та Stateless?

TL; DR: Віджет, що дозволяє оновити екран, є віджетом Stateful. Віджет, який не має статусу без громадянства.

Більш детально, динамічний віджет із вмістом, який може змінюватися, повинен бути віджетом Stateful. Віджет без громадянства може змінювати вміст лише тоді, коли параметри змінюються, а отже, це потрібно робити над точкою його розташування в ієрархії віджетів. Екран або віджет, що містить статичний вміст, повинен бути віджетом без стану, але щоб змінити вміст, він повинен мати статус.

Я знайшов цей відносний зміст у цікавій історії про носії. Ласкаво просимо!


4

Без стану: Віджет відтворення створює ТІЛЬКИ РАЗ, тоді він може оновлювати значення, але не явно. Це зрозуміло звідти і структура. Ось чому він має лише один клас, який поширюється на StatelessWidget. Тому, якщо я кажу, вони ніколи не зможуть повторно запустити build()метод знову.

Stateful : Віджети можуть оновлювати свої STATE (локально) та значення кілька разів після активації події . Ось причина, реалізація також різна. У цьому ми маємо 2 класи, один - це StatefulWidget, а другий - це обробник реалізації держави, тобто State<YourWidget>. Отже, якщо я кажу, вони можуть повторно запускати build()метод знову і знову на основі ініційованих подій.

Нижче наведена схема допоможе.

введіть тут опис зображення


1

Під час написання програми ви зазвичай створюєте нові віджети, які є підкласами StatelessWidget або StatefulWidget.

Ось деякі відмінності між StatelessWidgetі StatefulWidgetвіджетами:

Віджет без громадянства:

  1. Віджет із незмінним станом.
  2. Віджети без громадянства - це статичні віджети.
  3. Вони не залежать від будь-яких змін даних або будь-якої зміни поведінки.
  4. Віджети без громадянства не мають стану, вони будуть відтворені один раз і не оновлюватимуться самі, а будуть оновлюватися лише при зміні зовнішніх даних.
  5. Наприклад: Text, Icon, RaisedButtonє Апатриди віджетів.

Віджет без громадянства:

  1. Віджет із змінним станом.
  2. Державні віджети - це динамічні віджети.
  3. Їх можна оновлювати під час виконання на основі дії користувача або зміни даних.
  4. Віджети, що містять дані, мають внутрішній стан і можуть повторно відображатись, якщо вхідні дані змінюються або якщо віджет змінюється.
  5. Для прикладу: Checkbox, Radio Button, Sliderє Stateful віджети

0

Простими словами:

Як ми знаємо, кожен віджет - це вигляд у суєті. Яка має свої класи. Коли ми використовуємо ці класи, ми створюємо його об'єкт. Ми надаємо значення різним змінним / властивостям. Напр. Ми створюємо текстовий віджет, щоб ми могли надати йому рядок, колір, розмір шрифту, сімейство шрифтів. Отже, даючи це, ми визначаємо його властивості, створюючи його. До цього моменту віджети без громадянства чи державного зв’язку однакові, але,

Коли ми хочемо змінити / оновити його властивості (скажімо, Рядок або Колір) знову і знову після цього, це повинен віджет Stateful.

І коли ми не хочемо змінювати його властивості після першого визначення, це віджет без стану.

це означає, що ми дбаємо про дані, які віджет зберігає / контролює / показує.

Отже, Stateless - це менше даних, а Stateful - повна.

Тепер, якщо ви визначите клас, який не має стану, це означає, що цей клас не цікавить / не має змінних у собі або не каже дані у своєму власному класі, тобто рівні класу, але він може мати в собі інший віджет / клас, який піклується про дані, тобто він є державним . Тож це ніяк не впливає один на одного.

Будь ласка, виправте мене, якщо я тут помиляюся.


0

Що таке віджети Stateful та Stateless?

Віджет без громадянства: Віджет без громадянства будується лише тоді, коли він має батьківські зміни.

Віджети, що містять статус: Повні віджети штату містять стан віджета і можуть бути відновлені при зміні стану.


0

застереження: - почав працювати над флаттером з минулого тижня :)

Віджет без громадянства та повноцінний має власний життєвий цикл для створення та оновлення інтерфейсу користувача. однак ви можете використовувати або stateless, або statefull для візуалізації інтерфейсу, але практично statefull є більш зручним, коли ui повністю або частково залежить від зовнішніх даних (наприклад, - рендерінг списку за допомогою api), тоді як використання віджета без стану для відображення статичного інтерфейсу, як будь-який екран введення хороша практика.


1
Гадаю, автор мав на увазі протилежне: · D
Roc Boronat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.