Как использовать условный оператор в дочернем атрибуте виджета 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
виджет
Вы можете использовать конструктор в следующем составе: я рассмотрел условие, при котором мы можем получить 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, );
}
}
Есть две возможности:
- если вы используете только один виджет
Решение=>
Visibility(
visible: condition == true,
child: Text(""),
),
OR
Offstage(
offstage: condition == false,
child: Text(""),
),
- если вы используете два виджета или более
Решение=>
bool _visibility = false;
isVisible?
Widget1
:
WIdget2
bool isValid=true;
Center(
child:isValid==true?Text("IsValid"):Text("IsInvalid"),
),