Як використовувати умовний вираз у дочірньому атрибуті Flutter Widget (Center Widget)


130

До цього часу, коли мені потрібно було використовувати умовний оператор у віджеті, я робив наступне (використовуючи Центр та Контейнери як спрощені фіктивні приклади):

new Center(
  child: condition == true ? new Container() : new Container()
)

Хоча, коли я намагався використовувати оператор if / else, це призведе до попередження про мертвий код:

new Center(
  child: 
    if(condition == true){
      new Container();
    }else{
      new Container();
    }
)

Цікаво, що я спробував із заявою switch case, і це дає мені те саме попередження, і тому я не можу запустити код. Я роблю щось не так, чи це так, що ніхто не може використовувати if / else або міняти оператори, не хвилюючись, думаючи, що мертвий код?


1
Якщо ви хочете вставити блок, де слід створювати екземпляри віджетів, напевно, краще побудувати свій віджет за методами класу
aziza

Центр (дочірній: Builder (builder: (context) {if (true) return widget1 (); else return widget2 ();}))
Avnish kumar

Відповіді:


157

Насправді ви можете використовувати if/elseіswitch будь-який інший вислів, вбудований у дротик / трепет.

Використовуйте негайну анонімну функцію

class StatmentExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Text((() {
      if(true){
        return "tis true";}

      return "anything but true";
    })());
  }
}

тобто оберніть ваші оператори у функції

(() {
  // your code here
}())

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

Використовуйте тернарний оператор

condition ? Text("True") : null,

Використовуйте If або For оператори або оператори поширення в колекціях

children: [
  ...manyItems,
  oneItem,
  if(canIKickIt)
    ...kickTheCan
  for (item in items)
    Text(item)

Використовуйте метод

child: getWidget()

Widget getWidget() {
  if (x > 5) ...
  //more logic here and return a Widget

Перевизначити оператор перемикання

В якості іншої альтернативи тернарному оператору ви можете створити функціональну версію оператора switch, наприклад, у наступному дописі https://stackoverflow.com/a/57390589/1058292 .

  child: case2(myInput,
  {
    1: Text("Its one"),
    2: Text("Its two"),
  }, Text("Default"));

9
На мій погляд, це найбільш повна відповідь, дякую @orangesherbert
Daniel

2
Просто примітка, якщо хтось застряє, якщо ви використовуєте Провайдера для відновлення віджетів при глобальній зміні стану, і Ви отримуєте дані через "Provider.of", Ваш умовний оператор може не переглядатись, доки якісь інші дії не відновлять Ваш віджет. . Вам потрібно отримати вашу умовну змінну через "Споживач", яка повертається до функції побудови віджетів, тоді ваш умовний оператор повинен бути належним чином переоцінений як глобальні зміни стану.
Matthew Rideout

Одна з найкращих речей для хороших практик у дротику / тремтінні
Кольс,

72

У Дарті if/elseі switchвисловлювання не є виразами. Вони не повертають значення, тому ви не можете передати їх параметрам конструктора. Якщо у вашому методі побудови багато умовної логіки, тоді спробувати спростити його є гарною практикою. Наприклад, ви можете перенести самостійну логіку до методів і використовувати if/elseоператори для ініціалізації локальних змінних, які згодом можна використовувати.

За допомогою методу та if / else

Widget _buildChild() {
  if (condition) {
    return ...
  }
  return ...
}

Widget build(BuildContext context) {
  return new Container(child: _buildChild());
}

Використання if/else

Widget build(BuildContext context) {
  Widget child;
  if (condition) {
    child = ...
  } else {
    child = ...
  }
  return new Container(child: child);
}

1
Це повинна бути правильна відповідь! Дякую за це роз'яснення, що мені допомогло!
Slamit

35

Для запису Dart 2.3 додав можливість використовувати оператори if / else у літералах Collection. Тепер це робиться наступним чином:

return Column(children: <Widget>[
  Text("hello"),
  if (condition)
     Text("should not render if false"),
  Text("world")
],);

Flutter Issue # 28181 - Вбудований умовний візуалізація у списку


У мене є dart 2.5, але я отримую помилку під час запуску вище коду. У ньому сказано, що цей код повинен бути сумісним із попередніми версіями. Спробуйте оновити SDK constraints`
Асім

еммм, цікаво ~
Хаоджен

Чи додають вони функцію циклу? якщо так, то як це реалізувати?
princebillyGK


Чи не працює з одним віджетом , як AppBar -> leading:абоchild:
Alex Ванг

33

У такому випадку я б рекомендував використовувати тернарний оператор:

child: condition ? Container() : Center()

і спробуйте уникнути коду форми:

if (condition) return A else return B

що є непотрібним багатослівним, ніж тернарний оператор.

Але якщо потрібно більше логіки, ви також можете:

Використовуйте віджет Builder

Builder віджет призначений для забезпечення можливості використання закриття , коли дочірній віджет потрібно:

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

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

Ви використовуєте віджет Builder як дочірній матеріал, ви вказуєте свою логіку в його builderметоді:

Center(
  child: Builder(
    builder: (context) {
      // any logic needed...
      final condition = _whateverLogicNeeded();
      
      return condition
          ? Container();
          : Center();
    }
  )
)

Конструктор надає зручне місце для утримання творчої логіки. Це більш просто, ніж безпосередня анонімна функція, запропонована atreeon.

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


це спрацювало для мене досить добре для клацання предметів ящика та оновлення тіла
Швидке навчання

23

Я з’ясував, що простий спосіб використовувати умовну логіку для побудови інтерфейсу Flutter - це тримати логіку поза інтерфейсом. Ось функція повернення двох різних кольорів:

Color getColor(int selector) {
  if (selector % 2 == 0) {
    return Colors.blue;
  } else {
    return Colors.blueGrey;
  }
}

Функція використовується нижче, щоб встановити фон CircleAvatar.

new ListView.builder(
  itemCount: users.length,
  itemBuilder: (BuildContext context, int index) {
    return new Column(
      children: <Widget>[
        new ListTile(
          leading: new CircleAvatar(
            backgroundColor: getColor(index),
            child: new Text(users[index].name[0])
          ),
          title: new Text(users[index].login),
          subtitle: new Text(users[index].name),
        ),
        new Divider(height: 2.0),
      ],
    );
  },
);

Дуже акуратно, оскільки ви можете повторно використовувати функцію вибору кольору в декількох віджетах.


2
Я спробував це і працював для мене точно. Дякую
Аджай Кумар,

18

Я особисто використовую оператор if / else у дітей із подібним блоком. Він підтримує лише версію Dart 2.3.0 вище.

якщо / ще

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
        ] else ...[
          StatsScreen(),
        ],
    ],
 ),

якщо / ще якщо

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
        ] else if(_selectedIndex == 1)...[
          StatsScreen(),
        ],
    ],
 ),

17

Ви можете просто використати умовне твердження a==b?c:d

Наприклад :

Container(
  color: Colors.white,
  child: ('condition')
  ? Widget1(...)
  : Widget2(...)
)

Сподіваюсь, ідея вам зрозуміла.

Припустимо, якщо немає жодної іншої умови, ви можете використовувати SizedBox.shrink ()

Container(
      color: Colors.white,
      child: ('condition')
       ? Widget1(...)
       : SizedBox.shrink()
    )

Якщо це стовпець, не потрібно писати ?:оператор

Column(
 children: <Widget>[
  if('condition')
    Widget1(...),
 ],
)

1
Що робити, якщо немає іншої умови? У стовпцях сказати a == b? C: null не буде працювати
cwhisperer

1
Ви можете просто використовувати SizedBox.shrick () як другий віджет. оновлення відповіді.
Afinas EM

1
Якщо це стовпець, то ви можете використовувати if умову безпосередньо без іншого випадку: `if ('condition') widget () '
Afinas EM

10

Ось рішення. Я це виправив. Ось код

child: _status(data[index]["status"]),

Widget _status(status) {
  if (status == "3") {
    return Text('Process');
  } else if(status == "1") {
    return Text('Order');
  } else {
    return Text("Waiting");
  }
}

Як ним користуватися
Арді

6

якщо ви використовуєте список віджетів, ви можете використовувати це:

class HomePage extends StatelessWidget {
  bool notNull(Object o) => o != null;
  @override
  Widget build(BuildContext context) {
    var condition = true;
    return Scaffold(
      appBar: AppBar(
        title: Text("Provider Demo"),
      ),
      body: Center(
          child: Column(
        children: <Widget>[
          condition? Text("True"): null,
          Container(
            height: 300,
            width: MediaQuery.of(context).size.width,
            child: Text("Test")
          )
        ].where(notNull).toList(),
      )),
    );
  }
}

хвороба? Текст ("True"): нуль, це робить помилку Asertion false у консолі під час виконання
exequielc

@exequielc ви повинні додати .where (notNull) .toList () та кінець WidgetList та метод bool notNull (Object o) => o! = null ;. Спробуйте цілий приклад ...
Тобіас

1
Станом на Дарт 2.3 для умовного включення віджету до списку ви можете використовувати: [Текст ("Привіт"), якщо (світ) Текст ("Світ")]
Бретт Саттон,

4

Інша альтернатива: дляswitch's подібних висловлювань із великою кількістю умов я люблю використовувати карти:

return Card(
        elevation: 0,
        margin: EdgeInsets.all(1),
        child: conditions(widget.coupon)[widget.coupon.status] ??
            (throw ArgumentError('invalid status')));


conditions(Coupon coupon) => {
      Status.added_new: CheckableCouponTile(coupon.code),
      Status.redeemed: SimpleCouponTile(coupon.code),
      Status.invalid: SimpleCouponTile(coupon.code),
      Status.valid_not_redeemed: SimpleCouponTile(coupon.code),
    };

Додавати / видаляти елементи до списку умов простіше, не торкаючись умовного оператора.

Інший приклад:

var condts = {
  0: Container(),
  1: Center(),
  2: Row(),
  3: Column(),
  4: Stack(),
};

class WidgetByCondition extends StatelessWidget {
  final int index;
  WidgetByCondition(this.index);
  @override
  Widget build(BuildContext context) {
    return condts[index];
  }
}

3

Лол через місяці використання?: Я просто з'ясовую, що можу використовувати це:

Column(
     children: [
       if (true) Text('true') else Text('false'),
     ],
   )

2

Це чудова стаття та розмова. Я намагався використовувати тернарний оператор, як описано. Але код не працював, що призвело до помилки, як згадувалося.

Column(children: [ condition? Text("True"): null,],);

Трійковий приклад, наведений вище, пропускає провід. Дарт відповість помилкою, що замість віджета було повернуто null. Ви не можете повернути значення null. Правильним способом буде повернення віджета:

Column(children: [ condition? Text("True"): Text("false"),],); 

Для того, щоб тернар працював, вам потрібно повернути віджет. Якщо ви не хочете нічого повертати, ви можете повернути порожній контейнер.

Column(children: [ condition? Text("True"): Container(),],); 

Удачі.


2

За допомогою кнопки

bool _paused = false;

CupertinoButton(
  child: _paused ? Text('Play') : Text('Pause'),
  color: Colors.blue,
  onPressed: () {
    setState(() {
      _paused = !_paused;
    });
  },
),

1

**** Ви також можете використовувати умови, використовуючи цей метод ** **

 int _moneyCounter = 0;
  void _rainMoney(){
    setState(() {
      _moneyCounter +=  100;
    });
  }

new Expanded(
          child: new Center(
            child: new Text('\$$_moneyCounter', 

            style:new TextStyle(
              color: _moneyCounter > 1000 ? Colors.blue : Colors.amberAccent,
              fontSize: 47,
              fontWeight: FontWeight.w800
            )

            ),
          ) 
        ),

1

Якщо ви хочете зробити умовний візуалізацію, ви можете зробити це:

Column(
   children: <Widget>[
     if (isCondition == true)
        Text('The condition is true'),
   ],
 );

Але що, якщо ви хочете скористатися третинним (якщо-ще) станом? коли дочірній віджет є багатошаровим.

Ви можете використовувати це для свого рішення flutter_conditional_rendering пакет flutter, який покращує умовний візуалізацію, підтримує if-else та умови перемикання.

Якщо інше стан:

Column(
      children: <Widget>[
        Conditional.single(
          context: context,
          conditionBuilder: (BuildContext context) => someCondition == true,
          widgetBuilder: (BuildContext context) => Text('The condition is true!'),
          fallbackBuilder: (BuildContext context) => Text('The condition is false!'),
        ),
      ],
    );

Умова перемикача:

Column(
      children: <Widget>[
        ConditionalSwitch.single<String>(
          context: context,
          valueBuilder: (BuildContext context) => 'A',
          caseBuilders: {
            'A': (BuildContext context) => Text('The value is A!'),
            'B': (BuildContext context) => Text('The value is B!'),
          },
          fallbackBuilder: (BuildContext context) => Text('None of the cases matched!'),
        ),
      ],
    );

Якщо ви хочете умовно відтворити список віджетів (List<Widget>)замість одного. Використовуйте Conditional.list()таConditionalSwitch.list()!


1

У своєму додатку я створив WidgetChooserвіджет, щоб я міг вибирати між віджетами без умовної логіки:

WidgetChooser(
      condition: true,
      trueChild: Text('This widget appears if the condition is true.'),
      falseChild: Text('This widget appears if the condition is false.'),
    );

Це джерело WidgetChooserвіджета:

import 'package:flutter/widgets.dart';

class WidgetChooser extends StatelessWidget {
  final bool condition;
  final Widget trueChild;
  final Widget falseChild;

  WidgetChooser({@required this.condition, @required this.trueChild, @required this.falseChild});

  @override
  Widget build(BuildContext context) {
    if (condition) {
      return trueChild;
    } else {
      return falseChild;
    }
  }
}

Дуже корисно, дякую за поділ!
Петро

1

Ви можете використовувати тернарний оператор для умовних операторів у дротику, це просто

(condition) ? statement1 : statement2

якщо значення " conditionістина", то statement1буде виконано інакше statement2.

Беремо практичний приклад

Center(child: condition ? Widget1() : Widget2())

Пам'ятайте, якщо ви збираєтеся використовувати, nullоскільки Widget2це краще використовувати, SizedBox.shrink()оскільки деякі батьківські віджети видадуть виняток після отримання nullдитини.


-4

Тільки якщо вібровіджет

if(bool = true) Container(

child: ....

),

OR

if(bool = true) Container(

child: ....

) else new Container(child: lalala),
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.