Как использовать условный оператор в дочернем атрибуте виджета Flutter (Center Widget)

До сих пор всякий раз, когда мне нужно было использовать условный оператор в виджете, я делал следующее (используя Center и Containers как упрощенные фиктивные примеры):

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 или switch без трепета, думая, что это мертвый код?

35 ответов

На самом деле вы можете использовать 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

В качестве другой альтернативы троичному оператору вы можете создать функциональную версию оператора switch, например, в следующем посте /questions/49617032/drotik-chereduetsya-mnogo-esli/49617039#49617039.

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

Я лично использую оператор 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(),
        ],
    ],
 ),

В дартс, if/else а также switch являются заявлениями, а не выражениями. Они не возвращают значение, поэтому вы не можете передать их в параметры конструктора. Если в вашем методе сборки много условной логики, то стоит попробовать упростить ее. Например, вы можете переместить автономную логику в методы и использовать 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);
}

Виджет Builder предназначен для этого:

Платонический виджет, вызывающий закрытие для получения дочернего виджета.

Вы используете виджет Builder как дочерний и предоставляете свою логику в его builderметод. В вашем примере это идет:

Center(
  child: Builder(
    builder: (context) {
      if (condition == true) {
        return Container();
      } else {
        return Center();
      }
    }
  )
)

Я согласен с другими постерами, что логику следует извлекать из кода пользовательского интерфейса, но когда это только switch или if/elseОператор, используемый для определения виджета для создания, я предпочитаю оставить его там (при условии, что условие простое, например значение в ViewModel). В этом может помочь виджет Builder.

К слову, в Dart 2.3 добавлена ​​возможность использовать операторы if/else в литералах Collection. Теперь это делается следующим образом:

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

Ошибка Flutter № 28181 - Встроенный условный рендеринг в списке

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

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

Самый простой способ:

      // the ternary operator:
<conditon>
  ? Widget1(...)
  : Widget2(...)

// Or:
if (condition)
    Widget1(...)

// With else/ if else
if (condition1)
    Widget1(...)
else if (condition2)
    Widget2(...)
else
    Widget3(...),

Если вы хотите отображать НЕСКОЛЬКО виджетов для одного условия , вы можете использовать оператор распространения :

      if (condition) ...[
    Widget1(...),
    Widget2(...),
  ],

// with else / else if:
if (condition1) ...[
    Widget1(...),
    Widget2(...),
  ]
else if(condition2)...[
    Widget3(...),
    Widget4(...),
]
else ...[
    Widget3(...),
    Widget4(...),
],

Вы можете просто использовать условный оператор 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(...),
 ],
)

Помимо тернарного оператора, вы также можете использовать Builder виджет, если у вас есть операция, которую нужно выполнить перед оператором условия.

      Container(
  child: Builder(builder: (context) {
     /// some operation here ...
     if(someCondition) {
       return Text('A');
     }
     else return Text('B');
    })
 )

Lol после месяцев использования?: Я просто узнал, что могу использовать это:

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

Вот решение. Я исправил это. Вот код

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");
  }
}

Другая альтернатива: для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];
  }
}

Если вы используете список виджетов, вы можете использовать это:

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(),
      )),
    );
  }
}

Лучший способ

       Column(
        children: [
            if (firstCondition == true) ...[
              DayScreen(),
            ] else if(secondCondition == true)...[
              StatsScreen(),
            ], else...[
              StatsScreen(),
            ],
        ],
     ),

Пример практики:

С кнопкой

bool _paused = false;

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

В своем приложении я создал 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;
    }
  }
}

**** Вы также можете использовать условия, используя этот метод ** **

 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
            )

            ),
          ) 
        ),

В flutter, если вы хотите сделать условный рендеринг, вы можете сделать это:

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

Но что, если вы хотите использовать третичное условие (если-еще)? когда дочерний виджет является многослойным.

Вы можете использовать это для решения https://pub.dev/packages/flutter_conditional_rendering пакета flutter, который улучшает условный рендеринг, поддерживает if-else и условия переключения.

Условие 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()!

Вы можете использовать тернарный оператор для условных операторов в dart, его использование просто

(condition) ? statement1 : statement2

если condition верно, то statement1 будет выполнено иначе statement2.

На практическом примере

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

Помните, собираетесь ли вы использовать null в виде Widget2 лучше использовать SizedBox.shrink() потому что некоторые родительские виджеты выдают исключение после получения null ребенок.

Я предпочитаю использовать Map<String, Widget>

      Map<String, Widget> pageSelector = {
"login": Text("Login"),
"home": Text("Home"),
}

и внутри функции сборки я передаю ключ карте, как это

      new Center(
 child: pageSelector["here pass the key"] ?? Text("some default widget"),
)

или другое решение - использовать простую функцию

      Widget conditionalWidget(int numberToCheck){
 switch(numberToCheck){
   case 0: return Text("zero widget");
   case 1: return Text("one widget");
   case 2: return Text("two widget");
   case 3: return Text("three widget");
   default: return Text("default widget");
}

и внутри функции сборки передайте номер виджета или любой другой параметр для проверки

      new Center(
 child: conditionalWidget(pageNumber),
)

На мой взгляд, лучший и самый чистый способ , который я предпочитаю, - это создать вспомогательный класс функции typedef coditional_widget.dart.

      typedef IfWidget = List<Widget> Function(bool, Widget);
typedef IfElseWidget = Widget Function(bool, Widget, Widget);
typedef ElseEmptyWidget = Widget Function(bool, Widget);

IfWidget ifTrueWidget =
    (bool condition, Widget child) => [if (condition) child];

IfElseWidget ifElseWidget =
    (bool condition, Widget isTrueChild, Widget isFalseChild) =>
        condition ? isTrueChild : isFalseChild;

ElseEmptyWidget elseEmptyWidget = (bool condition, Widget isTrueChild) =>
    condition ? isTrueChild : const SizedBox.shrink();

Как это использовать

      // IfWidget 
  ** Row/ Column / Wrap child etc.
   children: <Widget>[
      ...ifWidget(title != null, Text('Only Display for True Conditon')),
      ]

// elseEmptyWidget
  ** Row/ Column / Wrap child etc.
   children: <Widget>[
          
      elseEmptyWidget(title!=null,Text('Only Display for True Conditon')),
      ]



// ifElseWidget
      ** Row/ Column / Wrap child etc.
       children: <Widget>[
            ifElseWidget(true,Text('Only Display for True Conditon'),Text('Only Display for false Conditon')),
          ]

это всего лишь несколько, вы можете добавить больше

Понятия не имею, что это хорошая практика! Но я использую pageValue ==1? Conatainer(): pageValue ==2? Текст ():pageValue ==3? SizrdBox(): Загрузчик ()

Это отличная статья и беседа. Я попытался использовать тернарный оператор, как описано. Но код не работал, что привело к упомянутой ошибке.

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

Приведенный выше троичный пример - это промахи. Дарт ответит ошибкой, что вместо виджета был возвращен нуль. Вы не можете вернуть null. Правильный способ - вернуть виджет:

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

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

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

Удачи.

Если вы хотите избежать использования операторов if, вы можете использовать Flutter Visibilityвиджет

Смотрите документацию здесь

Используйте conditional_builder 1.0.2

см. ссылку ниже

кликните сюда

Вы можете использовать конструктор в следующем составе: я рассмотрел условие, при котором мы можем получить URL-адрес изображения как нулевой, поэтому, если он равен нулю, я показываю коробку с уменьшенным размером, поскольку у нее нет свойства полностью недействительного виджета.

      Builder(builder: (BuildContext context) {
  if (iconPath != null) {
    return ImageIcon(
      AssetImage(iconPath!),
      color: AppColors.kPrimaryColor,
    );
  } else {
    return SizedBox.shrink();
  }
})

Условный рендеринг во Flutter можно легко выполнить с помощью пакета Proviso . Он имеет полный набор условных виджетов и построителей, чтобы сделать код условного оператора более читаемым и простым.

API и помощники включают, но не ограничиваются:

условные виджеты и конструкторы:

      ConditionWidget(
  condition: starred,
  widget: Icon(
    Icons.favorite
  ),
  fallback: fallbackWidget
)

ConditionBuilder(
  condition: (_) => someCondition,
  trueBuilder: (_) => trueWidget,
  fallbackBuilder: (_) => fallbackWidget
)

условия переключения:

      SwitchCaseBuilder.widget<String>(
  context: context,
  condition: (_) => '1',
  caseBuilders: {'1': (_) => someWidget(), '2': (_) => someWidget()},
  fallbackBuilder: (_) => fallbackWidget,
);  

или даже условный родительский виджет

      ConditionalWrap(
  shouldWrap: shouldWrapChildInParent,
  child: Container(),
  parentBuilder: (child) => Container(
    child: child,
  ),
)

API поддерживает отрисовку одного или нескольких виджетов. Вы можете попробовать.

Если вы хотите использовать оператор if вText()виджет, вы можете использоватьAnonymous functionвот так:

      class ConditionalStatmentExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Text(
     (() {
      if(true){
        return "return a string";
      }

      return "any other string when the condition is not met";
     })(),
     textAlign: TextAlign.center, );
  }
}

Есть две возможности:

  1. если вы используете только один виджет

Решение=>

           Visibility(
       visible: condition == true, 
       child: Text(""),
      ),
    OR

     Offstage(
       offstage: condition == false, 
       child: Text(""),
     ),
  1. если вы используете два виджета или более

Решение=>

            bool _visibility = false;
     
      isVisible?
          Widget1 
           :
          WIdget2
      bool isValid=true;

Center(
child:isValid==true?Text("IsValid"):Text("IsInvalid"),
),
Другие вопросы по тегам