Jak używać instrukcji warunkowej w atrybucie potomnym widżetu Flutter (środkowy widżet)

130

Do tej pory za każdym razem, gdy potrzebowałem użyć instrukcji warunkowej w widżecie, wykonałem następujące czynności (używając Centrum i kontenerów jako uproszczonych przykładów fikcyjnych):

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

Chociaż kiedy próbowałem użyć instrukcji if / else, doprowadziłoby to do ostrzeżenia o martwym kodzie:

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

Co ciekawe, próbowałem z instrukcją switch case i daje mi to to samo ostrzeżenie i dlatego nie mogę uruchomić kodu. Czy robię coś źle, czy jest tak, że nie można używać instrukcji if / else lub switch bez trzepotania myśli, że jest martwy kod?

Marko
źródło
1
Jeśli chcesz wstawić blok, w którym powinny być uruchamiane widżety, prawdopodobnie lepiej zbuduj swój widżet w metodach klasowych
Aziza
Center (child: Builder (builder: (context) {if (true) return widget1 (); else return widget2 ();}))
Avnish kumar

Odpowiedzi:

157

Właściwie można używać if/elsei switchoraz wszelkie inne inline oświadczenie w dart / trzepotaniem przedsionków.

Użyj natychmiastowej funkcji anonimowej

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

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

tj. zawijaj swoje instrukcje w funkcję

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

Zdecydowanie odradzałbym umieszczanie zbyt dużej logiki bezpośrednio w `` znacznikach '' interfejsu użytkownika, ale odkryłem, że wnioskowanie o typie w Dart wymaga trochę pracy, więc może być czasami przydatne w takich scenariuszach.

Użyj operatora trójargumentowego

condition ? Text("True") : null,

Użyj instrukcji If lub For lub operatorów spreadów w kolekcjach

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

Użyj metody

child: getWidget()

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

Przedefiniuj instrukcję przełącznika

Jako inną alternatywę dla operatora trójargumentowego możesz utworzyć wersję funkcji instrukcji switch, na przykład w następującym poście https://stackoverflow.com/a/57390589/1058292 .

  child: case2(myInput,
  {
    1: Text("Its one"),
    2: Text("Its two"),
  }, Text("Default"));
atreeon
źródło
9
Moim zdaniem jest to najbardziej kompletna odpowiedź, dzięki @orangesherbert
Oniya Daniel
2
Po prostu uwaga, jeśli ktoś utknie, jeśli używasz Providera do odbudowy widżetów po globalnej zmianie stanu i otrzymujesz dane przez "Provider.of", twoja instrukcja warunkowa może nie zostać ponownie oceniona, dopóki inna akcja nie odbuduje twojego widżetu . Musisz pobrać zmienną warunkową za pośrednictwem „Konsumenta”, która jest zwracana do funkcji budowania widgetu, a następnie Twoja instrukcja warunkowa powinna zostać odpowiednio ponownie oceniona, gdy zmieni się stan globalny.
Matthew Rideout,
Jedna z najlepszych rzeczy do dobrych praktyk w dart / flutter
Kohls
72

W Dart if/elsei switchsą oświadczeniami , a nie wyrażeniami. Nie zwracają wartości, więc nie można ich przekazać do parametrów konstruktora. Jeśli masz dużo logiki warunkowej w swojej metodzie budowania, dobrą praktyką jest wypróbowanie jej uproszczenia. Na przykład możesz przenieść logikę niezależną do metod i użyć if/elseinstrukcji do zainicjowania zmiennych lokalnych, których możesz później użyć.

Korzystanie z metody i if / else

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

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

Korzystanie z if/else

Widget build(BuildContext context) {
  Widget child;
  if (condition) {
    child = ...
  } else {
    child = ...
  }
  return new Container(child: child);
}
Jonah Williams
źródło
1
To powinna być prawidłowa odpowiedź! Dziękuję za to wyjaśnienie, które mi pomogło!
Slamit
35

Dla przypomnienia, Dart 2.3 dodał możliwość używania instrukcji if / else w literałach kolekcji. Odbywa się to teraz w następujący sposób:

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

Flutter Issue # 28181 - Inline warunkowe renderowanie na liście

Haojen
źródło
Mam rzutkę 2.5, ale powyżej kodu pojawia się błąd. Mówi `` ten kod jest wymagany, aby był kompatybilny z wcześniejszymi wersjami. spróbuj zaktualizować ograniczenia SDK ”
Aseem,
emmm, interesujące ~
Haojen,
Czy dodają funkcję pętli? jeśli tak, jak to wdrożyć?
princebillyGK
Nie działa z jednym widżetem, takim jak AppBar -> leading:lubchild:
Alex Vang
33

W takim przypadku zalecałbym użycie operatora trójskładnikowego:

child: condition ? Container() : Center()

i staraj się unikać kodu formularza:

if (condition) return A else return B

który jest niepotrzebnie bardziej rozwlekły niż operator trójskładnikowy.

Ale jeśli potrzeba więcej logiki, możesz również:

Użyj widżetu Builder

Builder widget jest przeznaczona dla umożliwienia korzystania z zamknięciem, gdy dziecko widget jest wymagane:

Widżet platoniczny, który wywołuje zamknięcie w celu uzyskania widgetu podrzędnego.

Jest wygodny zawsze, gdy potrzebujesz logiki do zbudowania widgetu , pozwala uniknąć konieczności tworzenia dedykowanej funkcji.

Korzystasz z widżetu Builder jako dziecko, podajesz swoją logikę w jego buildermetodzie:

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

Konstruktor zapewnia wygodne miejsce do przechowywania logiki kreacji. Jest to prostsze niż bezpośrednia funkcja anonimowa proponowana przez atreeon.

Zgadzam się również, że logika powinna zostać wyodrębniona z kodu UI, ale kiedy jest to naprawdę logika UI, czasami jest bardziej czytelne, aby ją tam zachować.

mr_mmmmore
źródło
to zadziałało dla mnie całkiem nieźle w przypadku elementów szuflady, kliknij i zaktualizuj treść
Szybki uczeń
23

Dowiedziałem się, że łatwym sposobem użycia logiki warunkowej do zbudowania interfejsu użytkownika Fluttera jest utrzymanie logiki poza interfejsem użytkownika. Oto funkcja zwracająca dwa różne kolory:

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

Funkcja jest używana poniżej, aby ustawić tło 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),
      ],
    );
  },
);

Bardzo fajne, ponieważ możesz ponownie użyć funkcji selektora kolorów w kilku widżetach.

Willie Nandi
źródło
2
Próbowałem tego i pracowałem dla mnie dokładnie w ten sposób. Dzięki
Ajay Kumar
18

Osobiście używam instrukcji if / else u dzieci z tego rodzaju instrukcją blokową. Obsługuje tylko w wersji Dart 2.3.0 powyżej.

Jeśli inaczej

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

if / else if

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
        ] else if(_selectedIndex == 1)...[
          StatsScreen(),
        ],
    ],
 ),
brendan
źródło
17

Możesz po prostu użyć instrukcji warunkowej a==b?c:d

Na przykład :

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

Mam nadzieję, że wpadłeś na pomysł.

Załóżmy, że jeśli nie ma innego warunku, możesz użyć SizedBox.shrink ()

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

Jeśli jest to kolumna, nie trzeba pisać ?:operatora

Column(
 children: <Widget>[
  if('condition')
    Widget1(...),
 ],
)
Afinas EM
źródło
1
A jeśli nie ma innego warunku? W kolumnach stwierdzenie a == b? C: null nie zadziała
cwhisperer Kwietnia
1
Możesz po prostu użyć SizedBox.shrick () jako drugiego widżetu. aktualizacja odpowiedzi.
Afinas EM
1
Jeśli jest to kolumna, możesz użyć warunku if bezpośrednio, bez else case: `if ('condition') widget () '
Afinas EM
10

Oto rozwiązanie. Naprawiłem to. Oto kod

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
źródło
Jak go używać
ardi
6

jeśli używasz listy widżetów, możesz użyć tego:

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
źródło
stan: schorzenie? Tekst („True”): null, powoduje to błąd Asertion false w konsoli, podczas wykonywania w czasie wykonywania
exequielc
@exequielc musisz dodać .where (notNull) .toList () i koniec WidgetList oraz metodę bool notNull (Object o) => o! = null ;. Wypróbuj cały przykład ...
Tobias,
1
Począwszy od Dart 2.3, aby warunkowo dołączyć widżet do listy, możesz użyć: [Text ("Hello"), if (world) Text ("World")]
Brett Sutton
4

Inna alternatywa: w przypadku switch'spodobnych stwierdzeń, z wieloma warunkami, lubię używać map:

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

Łatwiej jest dodawać / usuwać elementy do listy warunków bez dotykania instrukcji warunkowej.

Inny przykład:

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
źródło
3

Lol po miesiącach używania?: Po prostu dowiaduję się, że mogę tego użyć:

Column(
     children: [
       if (true) Text('true') else Text('false'),
     ],
   )
LudmilKirov
źródło
2

To świetny artykuł i rozmowa. Próbowałem użyć operatora trójskładnikowego zgodnie z opisem. Ale kod nie działał, powodując błąd, jak wspomniano.

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

Powyższy trójskładnikowy przykład nie prowadzi. Dart odpowie błędem, że zamiast widżetu zwrócono wartość null. Nie możesz zwrócić wartości null. Poprawnym sposobem będzie zwrócenie widżetu:

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

Aby trójka działała, musisz zwrócić Widget. Jeśli nie chcesz nic zwracać, możesz zwrócić pusty pojemnik.

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

Powodzenia.

Val
źródło
2

Z guzikiem

bool _paused = false;

CupertinoButton(
  child: _paused ? Text('Play') : Text('Pause'),
  color: Colors.blue,
  onPressed: () {
    setState(() {
      _paused = !_paused;
    });
  },
),
Rio Weber
źródło
1

**** Możesz także użyć warunków, używając tej metody ** **

 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
źródło
1

W flutter, jeśli chcesz wykonać renderowanie warunkowe, możesz zrobić to:

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

Ale co, jeśli chcesz użyć trzeciorzędnego warunku (jeśli-jeszcze)? gdy widget podrzędny jest wielowarstwowy.

Możesz użyć tego do rozwiązania flutter_conditional_rendering pakietu flutter, który ulepsza renderowanie warunkowe, obsługuje warunki if-else i switch.

Warunek Jeśli-Inaczej:

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

Stan przełącznika:

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

Jeśli chcesz warunkowo wyrenderować listę widżetów (List<Widget>)zamiast jednego. Użyj Conditional.list()iConditionalSwitch.list()!

Paresh Mangukiya
źródło
1

W mojej aplikacji utworzyłem WidgetChooserwidżet, dzięki czemu mogę wybierać między widżetami bez logiki warunkowej:

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

To jest źródło WidgetChooserwidgetu:

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
źródło
Bardzo przydatne, dzięki za udostępnienie!
Petro
1

Możesz użyć operatora trójargumentowego dla instrukcji warunkowych w dart, jego użycie jest proste

(condition) ? statement1 : statement2

jeśli conditionjest prawdziwe, to statement1zostanie wykonane w przeciwnym razie statement2.

Biorąc praktyczny przykład

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

Pamiętaj, jeśli zamierzasz używać, nullponieważ Widget2lepiej jest używać, SizedBox.shrink()ponieważ niektóre widżety nadrzędne będą zgłaszać wyjątek po uzyskaniu nulldziecka.

Raaj Patel
źródło
-4

Tylko jeśli wibruje widget

if(bool = true) Container(

child: ....

),

OR

if(bool = true) Container(

child: ....

) else new Container(child: lalala),
Renato Santos
źródło