Verwendung der bedingten Anweisung im untergeordneten Attribut eines Flutter-Widgets (Center-Widget)

126

Bisher habe ich Folgendes getan, wenn ich eine bedingte Anweisung in einem Widget verwenden musste (Verwenden von Center und Containern als vereinfachte Dummy-Beispiele):

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

Wenn ich jedoch versuchte, eine if / else-Anweisung zu verwenden, führte dies zu einer Dead-Code-Warnung:

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

Interessanterweise habe ich es mit einer switch case-Anweisung versucht, die mir dieselbe Warnung gibt und daher den Code nicht ausführen kann. Mache ich etwas falsch oder ist es so, dass man if / else- oder switch-Anweisungen nicht verwenden kann, ohne zu flattern, dass es toten Code gibt?

Marko
quelle
1
Wenn Sie einen Block einfügen möchten, in dem Widgets instanziiert werden sollen, sollten Sie Ihr Widget wahrscheinlich besser in Klassenmethoden
erstellen
Center (Kind: Builder (Builder: (Kontext) {if (true) return widget1 (); sonst return widget2 ();}))
Avnish kumar

Antworten:

146

Eigentlich Sie können verwenden if/elseund switchund andere Aussage Inline in dart / flattern.

Verwenden Sie eine sofortige anonyme Funktion

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

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

dh wickeln Sie Ihre Aussagen in eine Funktion

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

Ich würde dringend empfehlen, nicht zu viel Logik direkt mit Ihrem UI-Markup zu verknüpfen, aber ich fand, dass die Typinferenz in Dart ein wenig Arbeit erfordert, sodass sie in solchen Szenarien manchmal nützlich sein kann.

Verwenden Sie den ternären Operator

condition ? Text("True") : null,

Verwenden Sie If- oder For-Anweisungen oder Spread-Operatoren in Sammlungen

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

Verwenden Sie eine Methode

child: getWidget()

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

Switch-Anweisung neu definieren

Als weitere Alternative zum ternären Operator können Sie eine Funktionsversion der switch-Anweisung erstellen, z. B. im folgenden Beitrag https://stackoverflow.com/a/57390589/1058292 .

  child: case2(myInput,
  {
    1: Text("Its one"),
    2: Text("Its two"),
  }, Text("Default"));
atreeon
quelle
9
Meiner Meinung nach ist dies die vollständigste Antwort, danke @orangesherbert
Oniya Daniel
2
Nur ein Hinweis: Wenn jemand stecken bleibt, wenn Sie Provider verwenden, um Ihre Widgets bei einer globalen Statusänderung neu zu erstellen, und wenn Sie Daten über "Provider.of" erhalten, wird Ihre bedingte Anweisung möglicherweise nicht neu bewertet, bis eine andere Aktion Ihr Widget neu erstellt . Sie müssen Ihre bedingte Variable über "Consumer" abrufen, das an die Widget-Erstellungsfunktion zurückgegeben wird. Dann sollte Ihre bedingte Anweisung ordnungsgemäß neu bewertet werden, wenn sich der globale Status ändert.
Matthew Rideout
Eines der besten Dinge für gute Praktiken im Dart / Flattern
Kohls
72

In Dart if/elseund switchsind Anweisungen keine Ausdrücke. Sie geben keinen Wert zurück, sodass Sie sie nicht an Konstruktorparameter übergeben können. Wenn Ihre Erstellungsmethode viel bedingte Logik enthält, empfiehlt es sich, diese zu vereinfachen. Beispielsweise können Sie in sich geschlossene Logik in Methoden verschieben und if/elseAnweisungen verwenden, um lokale Variablen zu initialisieren, die Sie später verwenden können.

Mit einer Methode und wenn / sonst

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

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

Verwenden eines if/else

Widget build(BuildContext context) {
  Widget child;
  if (condition) {
    child = ...
  } else {
    child = ...
  }
  return new Container(child: child);
}
Jonah Williams
quelle
1
Dies sollte die richtige Antwort sein! Vielen Dank für diese Klarstellung, es hat mir geholfen!
Slamit
33

Für den Datensatz hat Dart 2.3 die Möglichkeit hinzugefügt, if / else-Anweisungen in Collection-Literalen zu verwenden. Dies geschieht nun folgendermaßen:

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

Flutter Issue # 28181 - Inline-bedingtes Rendern in der Liste

Haojen
quelle
Ich habe Dart 2.5, aber ich erhalte eine Fehlermeldung über dem Code. Es heißt, dieser Code muss mit früheren Versionen kompatibel sein. versuchen Sie, SDK-Einschränkungen zu aktualisieren`
Aseem
emmm, interessant ~
Haojen
Fügen sie eine Schleifenfunktion hinzu? Wenn ja, wie wird es implementiert?
princebillyGK
Funktioniert nicht mit einem einzelnen Widget wie AppBar -> leading:oderchild:
Alex Vang
30

Die anderen Antworten erwähnen es nicht, Sie können auch:

Verwenden Sie das Builder-Widget

Das Builder-Widget soll die Verwendung eines Abschlusses ermöglichen, wenn ein untergeordnetes Widget erforderlich ist:

Ein platonisches Widget, das einen Abschluss aufruft, um sein untergeordnetes Widget zu erhalten.

Es ist immer dann praktisch, wenn Sie Logik zum Erstellen eines Widgets benötigen keine dedizierte Funktion erstellen. Ich finde auch, dass es klarer macht, was getan wird, als eine sofortige anonyme Funktion zu verwenden.

Sie verwenden das Builder-Widget als untergeordnetes Element und geben Ihre Logik in seiner builderMethode an. Mit Ihrem Beispiel geht es:

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

In einem solchen trivialen Beispiel würde der ternäre Operator ausreichen ( child: condition ? Container() : Center()), aber wenn mehr Logik benötigt wird, bietet der Builder einen geeigneten Ort, um ihn zu halten.

Ich stimme auch anderen Postern zu, dass die Logik aus dem UI-Code extrahiert werden sollte, aber wenn es nur eine switchoder if/ else-Anweisung ist, die zum Bestimmen des zu erstellenden Widgets verwendet wird, ziehe ich es vor, sie dort zu belassen (vorausgesetzt, die Bedingung ist einfach, zum Beispiel das Testen von a Wert in einem ViewModel). Das Builder-Widget kann dabei helfen.

mr_mmmmore
quelle
Dies funktionierte ziemlich gut für mich beim Klicken und Aktualisieren des Schubladenartikels
Schnelllerner
22

Ich fand heraus, dass eine einfache Möglichkeit, bedingte Logik zum Erstellen der Flutter-Benutzeroberfläche zu verwenden, darin besteht, die Logik außerhalb der Benutzeroberfläche zu halten. Hier ist eine Funktion, um zwei verschiedene Farben zurückzugeben:

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

Die folgende Funktion wird verwendet, um den Hintergrund des CircleAvatar festzulegen.

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

Sehr ordentlich, da Sie Ihre Farbauswahlfunktion in mehreren Widgets wiederverwenden können.

Willie Nandi
quelle
1
Ich habe es versucht und genau so für mich gearbeitet. Vielen Dank
Ajay Kumar
17

Ich persönlich verwende die if / else-Anweisung bei Kindern mit dieser Art von Blockanweisung. Es wird nur von Dart Version 2.3.0 unterstützt.

ansonsten

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

wenn / sonst wenn

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

Sie können einfach eine bedingte Anweisung verwenden a==b?c:d

Zum Beispiel :

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

Ich hoffe du hast die Idee.

Angenommen, wenn keine andere Bedingung vorliegt, können Sie eine SizedBox.shrink () verwenden.

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

Wenn es sich um eine Spalte handelt, muss kein ?:Operator geschrieben werden

Column(
 children: <Widget>[
  if('condition')
    Widget1(...),
 ],
)
Afinas EM
quelle
1
Was ist, wenn keine andere Bedingung vorliegt? In Spalten funktioniert es nicht, a == b? C: null zu sagen
cwhisperer
1
Sie können einfach SizedBox.shrick () als zweites Widget verwenden. Aktualisierung der Antwort.
Afinas EM
1
Wenn es sich um eine Spalte handelt, können Sie if condition direkt ohne else case verwenden: `if ('condition') widget () '
Afinas EM
10

Hier ist die Lösung. Ich habe es repariert. Hier ist der Code

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");
  }
}
Yasir Malik
quelle
Wie man es benutzt
ardi
6

Wenn Sie eine Liste von Widgets verwenden, können Sie Folgendes verwenden:

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(),
      )),
    );
  }
}
Tobias
quelle
Bedingung? Text ("True"): null, dies führt zu einem Fehler. Asertion false in der Konsole bei der Laufzeitausführung
exequielc
@exequielc Sie müssen .where (notNull) .toList () und das Ende der WidgetList und die Methode bool notNull (Object o) => o! = null; hinzufügen. Versuchen Sie das ganze Beispiel ...
Tobias
1
Ab Dart 2.3 können Sie ein Widget bedingt in eine Liste aufnehmen, die Sie verwenden können: [Text ("Hallo"), if (Welt) Text ("Welt")]
Brett Sutton
4

Eine andere Alternative: Für ' switch's' ähnliche Aussagen mit vielen Bedingungen verwende ich gerne Karten:

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

Es ist einfacher, Elemente zur Bedingungsliste hinzuzufügen / zu entfernen, ohne die bedingte Anweisung zu berühren.

Ein anderes Beispiel:

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];
  }
}
alexpfx
quelle
3

Lol nach Monaten der Verwendung ?: Ich finde gerade heraus, dass ich dies verwenden kann:

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

Dies ist ein großartiger Artikel und ein großartiges Gespräch. Ich habe versucht, den ternären Operator wie beschrieben zu verwenden. Der Code funktionierte jedoch nicht und führte wie erwähnt zu einem Fehler.

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

Das obige ternäre Beispiel ist Miss Leading. Dart antwortet mit dem Fehler, dass anstelle des Widgets eine Null zurückgegeben wurde. Sie können nicht null zurückgeben. Der richtige Weg ist, ein Widget zurückzugeben:

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

Damit das Ternär funktioniert, müssen Sie ein Widget zurückgeben. Wenn Sie nichts zurückgeben möchten, können Sie einen leeren Container zurückgeben.

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

Viel Glück.

Val
quelle
2

Mit einem Knopf

bool _paused = false;

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

**** Mit dieser Methode können Sie auch Bedingungen verwenden ** **

 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
            )

            ),
          ) 
        ),
Hamza Tanveer
quelle
1

Wenn Sie im Flattern bedingtes Rendern ausführen möchten, können Sie Folgendes tun:

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

Aber was ist, wenn Sie eine tertiäre (wenn-sonst) Bedingung verwenden möchten? wenn das untergeordnete Widget mehrschichtig ist.

Sie können dies für die Lösung flutter_conditional_rendering verwenden, ein Flatterpaket , das das bedingte Rendern verbessert, if- else- und switch-Bedingungen unterstützt.

Wenn-sonst-Bedingung:

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!'),
        ),
      ],
    );

Schalterbedingung:

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!'),
        ),
      ],
    );

Wenn Sie eine Liste von Widgets (List<Widget>)anstelle eines einzelnen bedingt rendern möchten . Verwenden Sie Conditional.list()undConditionalSwitch.list()!

Paresh Mangukiya
quelle
1

In meiner App habe ich ein WidgetChooserWidget erstellt, damit ich zwischen Widgets ohne bedingte Logik wählen kann:

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

Dies ist die Quelle für das WidgetChooserWidget:

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;
    }
  }
}
jon
quelle
Sehr nützlich, danke fürs Teilen!
Petro
1

Sie können den ternären Operator für bedingte Anweisungen in Dart verwenden. Die Verwendung ist einfach

(condition) ? statement1 : statement2

Wenn das conditionwahr ist, statement1wird das anders ausgeführt statement2.

Ein praktisches Beispiel nehmen

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

Denken Sie daran, ob Sie es verwenden möchten, nullda Widget2es besser ist, es zu verwenden, SizedBox.shrink()da einige übergeordnete Widgets eine Ausnahme auslösen, nachdem Sie ein nullKind erhalten haben.

Raaj Patel
quelle
-3

Nur wenn vibrierendes Widget

if(bool = true) Container(

child: ....

),

OR

if(bool = true) Container(

child: ....

) else new Container(child: lalala),
Renato Santos
quelle