Jak pracować ze wskaźnikiem postępu we flutter?


86

Jestem nowicjuszem w trzepotaniu i chciałem wiedzieć, jaki jest lepszy sposób na dodanie CircularProgressIndicatordo mojego układu. Na przykład mój widok logowania. Ten widok ma nazwę użytkownika, hasło i przycisk logowania. Chciałem stworzyć układ nakładki (z Opacity), który podczas ładowania wyświetla wskaźnik postępu, tak jak ja używam w NativeScript, ale nie jestem zdezorientowany, jak to zrobić, a także, czy jest to lepszy sposób. Na przykład w języku NativeScript dodaję IndicatorActivity w głównym układzie i ustawiam zajęty na true lub false, aby podczas ładowania nakładał się na wszystkie składniki widoku.

Edytować:

Udało mi się osiągnąć taki wynik:

    void main() {
      runApp(new MyApp());
    }

    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }

    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);

      final String title;

      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }

    class _MyHomePageState extends State<MyHomePage> {
      bool _loading = false;

      void _onLoading() {
        setState(() {
          _loading = true;
          new Future.delayed(new Duration(seconds: 3), _login);
        });
      }


      Future _login() async{
        setState((){
          _loading = false;
        });
      }

      @override
      Widget build(BuildContext context) {


          var body = new Column(
              children: <Widget>[
                new Container(
                  height: 40.0,
                  padding: const EdgeInsets.all(10.0),
                  margin: const EdgeInsets.fromLTRB(15.0, 150.0, 15.0, 0.0),
                  decoration: new BoxDecoration(
                    color: Colors.white,
                  ),
                  child: new TextField(
                    decoration: new InputDecoration.collapsed(hintText: "username"),
                  ),
                ),
                new Container(
                  height: 40.0,
                  padding: const EdgeInsets.all(10.0),
                  margin: const EdgeInsets.all(15.0),
                  decoration: new BoxDecoration(
                    color: Colors.white,
                  ),
                  child: new TextField(
                    decoration: new InputDecoration.collapsed(hintText: "password"),
                  ),
                ),
              ],
            );


          var bodyProgress = new Container(
            child: new Stack(
              children: <Widget>[
                body,
                new Container(
                  alignment: AlignmentDirectional.center,
                  decoration: new BoxDecoration(
                    color: Colors.white70,
                  ),
                  child: new Container(
                    decoration: new BoxDecoration(
                      color: Colors.blue[200],
                      borderRadius: new BorderRadius.circular(10.0)
                    ),
                    width: 300.0,
                    height: 200.0,
                    alignment: AlignmentDirectional.center,
                    child: new Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        new Center(
                          child: new SizedBox(
                            height: 50.0,
                            width: 50.0,
                            child: new CircularProgressIndicator(
                              value: null,
                              strokeWidth: 7.0,
                            ),
                          ),
                        ),
                        new Container(
                          margin: const EdgeInsets.only(top: 25.0),
                          child: new Center(
                            child: new Text(
                              "loading.. wait...",
                              style: new TextStyle(
                                color: Colors.white
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          );

          return new Scaffold(
            appBar: new AppBar(
              title: new Text(widget.title),
            ),
            body: new Container(
              decoration: new BoxDecoration(
                color: Colors.blue[200]
              ),
              child: _loading ? bodyProgress : body
            ),
            floatingActionButton: new FloatingActionButton(
              onPressed: _onLoading,
              tooltip: 'Loading',
              child: new Icon(Icons.check),
            ),
          );
      }
    }

wynik na ekranie aplikacji

Nadal dostosowuję się do idei stanów. Ten kod jest zgodny z oczekiwaniami podczas pracy z flutter?

Dzięki!


1
jak wyłączyć backpressed, gdy jest wyświetlane okno dialogowe?
Szybki uczeń

Odpowiedzi:


77

W przypadku flutter istnieje kilka sposobów radzenia sobie z akcjami asynchronicznymi.

Leniwy sposób na zrobienie tego może polegać na użyciu modalu. Który blokuje wprowadzanie danych przez użytkownika, zapobiegając w ten sposób niepożądanym działaniom. Wymagałoby to bardzo niewielkich zmian w kodzie. Po prostu zmodyfikuj swój _onLoadingna coś takiego:

void _onLoading() {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return Dialog(
        child: new Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            new CircularProgressIndicator(),
            new Text("Loading"),
          ],
        ),
      );
    },
  );
  new Future.delayed(new Duration(seconds: 3), () {
    Navigator.pop(context); //pop dialog
    _login();
  });
}

Najlepszym sposobem na to jest użycie FutureBuilderi widgetu stanowego. Od czego zacząłeś. Sztuczka polega na tym, że zamiast mieć boolean loading = falsew swoim stanie, możesz bezpośrednio użyćFuture<MyUser> user

A następnie przekaż go jako argument do FutureBuilder, co da ci pewne informacje, takie jak „hasData” lub wystąpienie MyUserpo zakończeniu.

Prowadziłoby to do czegoś takiego:

@immutable
class MyUser {
  final String name;

  MyUser(this.name);
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Future<MyUser> user;

  void _logIn() {
    setState(() {
      user = new Future.delayed(const Duration(seconds: 3), () {
        return new MyUser("Toto");
      });
    });
  }

  Widget _buildForm(AsyncSnapshot<MyUser> snapshot) {
    var floatBtn = new RaisedButton(
      onPressed:
          snapshot.connectionState == ConnectionState.none ? _logIn : null,
      child: new Icon(Icons.save),
    );
    var action =
        snapshot.connectionState != ConnectionState.none && !snapshot.hasData
            ? new Stack(
                alignment: FractionalOffset.center,
                children: <Widget>[
                  floatBtn,
                  new CircularProgressIndicator(
                    backgroundColor: Colors.red,
                  ),
                ],
              )
            : floatBtn;

    return new ListView(
      padding: const EdgeInsets.all(15.0),
        children: <Widget>[
          new ListTile(
            title: new TextField(),
          ),
          new ListTile(
            title: new TextField(obscureText: true),
          ),
          new Center(child: action)
        ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return new FutureBuilder(
      future: user,
      builder: (context, AsyncSnapshot<MyUser> snapshot) {
        if (snapshot.hasData) {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text("Hello ${snapshot.data.name}"),
            ),
          );
        } else {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text("Connection"),
            ),
            body: _buildForm(snapshot),
          );
        }
      },
    );
  }
}

1
Fajnie, oba przykłady przydadzą się przy logowaniu i innych sytuacjach. Postęp obsługi w oknie dialogowym wygląda lepiej niż moja wersja i FutureBuilder. Jest też bardziej elegancki niż moje rozwiązanie. dzięki za pomoc!
Ricardo Bocchi

pytanie niezwiązane z tematem .. do każdego pola tekstowego Potrzebuję unikalnego kontrolera TextEditingController?
Ricardo Bocchi

@RicardoBocchi Yes
aziza

Nie sądzę, aby Dialog zadziałał z rzeczywistym przykładem, jest mylące, w jaki sposób użytkownik zostanie przekierowany po zwróceniu _login (). Twój drugi przykład wydaje się o wiele wygodniejszy. Dobrze upieczony.
Aziza

1
Cóż, Dialog jest funkcjonalny i wymaga bardzo niewielkich modyfikacji jego oryginalnego kodu. Mógłby na przykład podążać za zamknięciem dialogu za pomocą Navigator.pushNamed("/home").
Rémi Rousselet

38

Dla mnie jednym fajnym sposobem na zrobienie tego jest pokazanie SnackBaru dołu podczas procesu logowania, oto przykład tego, co mam na myśli:

wprowadź opis obrazu tutaj

Oto jak skonfigurować SnackBar.

Zdefiniuj globalny klucz dla swojego Scaffold

final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

Dodaj to do swojego Scaffold keyatrybutu

return new Scaffold(
      key: _scaffoldKey,
.......

Oddzwanianie do mojego przycisku onPressedlogowania:

onPressed: () {
                  _scaffoldKey.currentState.showSnackBar(
                      new SnackBar(duration: new Duration(seconds: 4), content:
                      new Row(
                        children: <Widget>[
                          new CircularProgressIndicator(),
                          new Text("  Signing-In...")
                        ],
                      ),
                      ));
                  _handleSignIn()
                      .whenComplete(() =>
                      Navigator.of(context).pushNamed("/Home")
                  );
                }

To naprawdę zależy od tego, jak chcesz zbudować swój układ i nie jestem pewien, co masz na myśli.

Edytować

Prawdopodobnie chcesz tego w ten sposób, użyłem stosu, aby osiągnąć ten wynik i po prostu pokaż lub ukryj mój wskaźnik na podstawie onPressed

wprowadź opis obrazu tutaj

class TestSignInView extends StatefulWidget {
  @override
  _TestSignInViewState createState() => new _TestSignInViewState();
}


class _TestSignInViewState extends State<TestSignInView> {
  bool _load = false;
  @override
  Widget build(BuildContext context) {
    Widget loadingIndicator =_load? new Container(
      color: Colors.grey[300],
      width: 70.0,
      height: 70.0,
      child: new Padding(padding: const EdgeInsets.all(5.0),child: new Center(child: new CircularProgressIndicator())),
    ):new Container();
    return new Scaffold(
      backgroundColor: Colors.white,
      body:  new Stack(children: <Widget>[new Padding(
        padding: const EdgeInsets.symmetric(vertical: 50.0, horizontal: 20.0),
        child: new ListView(

          children: <Widget>[
            new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center
              ,children: <Widget>[
            new TextField(),
            new TextField(),

            new FlatButton(color:Colors.blue,child: new Text('Sign In'),
                onPressed: () {
              setState((){
                _load=true;
              });

                  //Navigator.of(context).push(new MaterialPageRoute(builder: (_)=>new HomeTest()));
                }
            ),

            ],),],
        ),),
        new Align(child: loadingIndicator,alignment: FractionalOffset.center,),

      ],));
  }

}

Cześć, właśnie to chciałem zrobić, ale nie dostałem układu, którego potrzebowałem. Stos jest odpowiedzią. O StatefulWidget, czy poprawne jest budowanie całego widoku, gdy zmienia się stan postępu?
Ricardo Bocchi

Hej, nie rozumiem twojego pytania?
Aziza

W moim kodzie po _loadingzmianie wszystkie widoki są odbudowywane. Czy tak jest?
Ricardo Bocchi

1
Korzystanie z modalu jest prawdopodobnie dużo łatwiejsze i jednocześnie bardziej intuicyjne. Możesz po prostu wcisnąć okno dialogowe ładowania na początku lub na żądanie, a po zakończeniu otworzyć je. Ma również tę zaletę, że zapobiega dalszemu wprowadzaniu danych przez użytkownika.
Rémi Rousselet

2
Okey, pozwól mi coś upiec.
Rémi Rousselet

34

Utwórz bool isLoadingi ustaw go na false. Za pomocą operatora trójargumentowego, gdy użytkownik kliknie przycisk logowania, ustawia stan isLoadingna true. Zamiast przycisku logowania otrzymasz okrągły wskaźnik ładowania

 isLoading ? new PrimaryButton(
                      key: new Key('login'),
                      text: 'Login',
                      height: 44.0,
                      onPressed: setState((){isLoading = true;}))
                  : Center(
                      child: CircularProgressIndicator(),
                    ),

Możesz zobaczyć zrzuty ekranu, jak to wygląda, zanim klikniesz przed zalogowaniem wprowadź opis obrazu tutaj

Po kliknięciu logowania wprowadź opis obrazu tutaj

W międzyczasie możesz uruchomić proces logowania i zalogować użytkownika. Jeżeli poświadczenia użytkownika są błędne znowu będzie setStateod isLoadingcelu false, tak że wskaźnik ładowania staną się niewidoczne i logowanie przycisk widoczny dla użytkownika. Nawiasem mówiąc, primaryButton użyty w kodzie jest moim przyciskiem niestandardowym. Możesz zrobić to samo z OnPressedin button.


To całkiem sprytne! Nie ma potrzeby obsługiwać podwójnego kliknięcia itp. Dzięki.
Benobab

jak poradzić sobie z podwójnym kliknięciem w trzepotaniu, jak ten scenariusz?

Nigdy nie miałem takiej sytuacji, aby obsłużyć podwójne dotknięcie, ponieważ po jednym dotknięciu zmienia się we wskaźnik ładowania. Zgodnie z moim zrozumieniem twojego komentarza, myślę, że możemy owinąć niestandardowy przycisk detektorem gestów, a następnie możesz pracować nad podwójnym dotknięciem.
Harsha pulikollu

Gdzie używać operatora trójskładnikowego? Twój przykład wygląda inteligentnie, ale nie wiesz, jak go wdrożyć.
Bikram Pahi

Użyj powyższego fragmentu kodu w metodzie kompilacji, w której chcesz mieć przycisk (logowanie). Kiedy użytkownik kliknie ten przycisk, bool (isLoading) staje się prawdą i zamiast przycisku pokazuje okrągły wskaźnik ładowania.
Harsha pulikollu

20

1. Bez wtyczki

    class IndiSampleState extends State<ProgHudPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('Demo'),
        ),
        body: Center(
          child: RaisedButton(
            color: Colors.blueAccent,
            child: Text('Login'),
            onPressed: () async {
              showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    return Center(child: CircularProgressIndicator(),);
                  });
              await loginAction();
              Navigator.pop(context);
            },
          ),
        ));
  }

  Future<bool> loginAction() async {
    //replace the below line of code with your login request
    await new Future.delayed(const Duration(seconds: 2));
    return true;
  }
}

2. Z wtyczką

sprawdź tę wtyczkę progress_hud

dodaj zależność w pliku pubspec.yaml

dev_dependencies:
  progress_hud: 

zaimportuj pakiet

import 'package:progress_hud/progress_hud.dart';

Przykładowy kod jest podany poniżej, aby pokazać i ukryć wskaźnik

class ProgHudPage extends StatefulWidget {
  @override
  _ProgHudPageState createState() => _ProgHudPageState();
}

class _ProgHudPageState extends State<ProgHudPage> {
  ProgressHUD _progressHUD;
  @override
  void initState() {
    _progressHUD = new ProgressHUD(
      backgroundColor: Colors.black12,
      color: Colors.white,
      containerColor: Colors.blue,
      borderRadius: 5.0,
      loading: false,
      text: 'Loading...',
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('ProgressHUD Demo'),
        ),
        body: new Stack(
          children: <Widget>[
            _progressHUD,
            new Positioned(
                child: RaisedButton(
                  color: Colors.blueAccent,
                  child: Text('Login'),
                  onPressed: () async{
                    _progressHUD.state.show();
                    await loginAction();
                    _progressHUD.state.dismiss();
                  },
                ),
                bottom: 30.0,
                right: 10.0)
          ],
        ));
  }

  Future<bool> loginAction()async{
    //replace the below line of code with your login request
    await new Future.delayed(const Duration(seconds: 2));
    return true;
  }
}

12
Nie głosuj w dół, niektórzy ludzie nie chcą zajmować się podstawowymi szczegółami interfejsu użytkownika i jestem jednym z nich, więc ta wtyczka jest przydatna
Vladtn

3
pasek postępu w api jest wystarczająco dobry, dodanie zależności zwiększa rozmiar kompilacji. już trzepotliwa konstrukcja jest nadmierna.
prashant0205

Czy naprawdę powinieneś dodać to jako zależność od deweloperów?
George,


1
@MohammadMeshkani use Navigator.pop (kontekst); przed przejściem do następnego ekranu
Shyju M

13

Krok 1: Utwórz okno dialogowe

   showAlertDialog(BuildContext context){
      AlertDialog alert=AlertDialog(
        content: new Row(
            children: [
               CircularProgressIndicator(),
               Container(margin: EdgeInsets.only(left: 5),child:Text("Loading" )),
            ],),
      );
      showDialog(barrierDismissible: false,
        context:context,
        builder:(BuildContext context){
          return alert;
        },
      );
    }

Krok 2: Zadzwoń

showAlertDialog(context);
await firebaseAuth.signInWithEmailAndPassword(email: email, password: password);
Navigator.pop(context);

Przykład z oknem i formularzem logowania

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class DynamicLayout extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new MyWidget();
    }
  }
showAlertDialog(BuildContext context){
  AlertDialog alert=AlertDialog(
    content: new Row(
        children: [
           CircularProgressIndicator(),
           Container(margin: EdgeInsets.only(left: 5),child:Text("Loading" )),
        ],),
  );
  showDialog(barrierDismissible: false,
    context:context,
    builder:(BuildContext context){
      return alert;
    },
  );
}

  class MyWidget extends State<DynamicLayout>{
  Color color = Colors.indigoAccent;
  String title='app';
  GlobalKey<FormState> globalKey=GlobalKey<FormState>();
  String email,password;
  login() async{
   var currentState= globalKey.currentState;
   if(currentState.validate()){
        currentState.save();
        FirebaseAuth firebaseAuth=FirebaseAuth.instance;
        try {
          showAlertDialog(context);
          AuthResult authResult=await firebaseAuth.signInWithEmailAndPassword(
              email: email, password: password);
          FirebaseUser user=authResult.user;
          Navigator.pop(context);
        }catch(e){
          print(e);
        }
   }else{

   }
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar:AppBar(
        title: Text("$title"),
        ) ,
          body: Container(child: Form(
            key: globalKey,
            child: Container(
              padding: EdgeInsets.all(10),
              child: Column(children: <Widget>[
              TextFormField(decoration: InputDecoration(icon: Icon(Icons.email),labelText: 'Email'),
              // ignore: missing_return
              validator:(val){
                if(val.isEmpty)
                  return 'Please Enter Your Email';
              },
              onSaved:(val){
                email=val;
              },
              ),
                TextFormField(decoration: InputDecoration(icon: Icon(Icons.lock),labelText: 'Password'),
             obscureText: true,
                  // ignore: missing_return
                  validator:(val){
                    if(val.isEmpty)
                      return 'Please Enter Your Password';
                  },
                  onSaved:(val){
                    password=val;
                  },
              ),
                RaisedButton(color: Colors.lightBlue,textColor: Colors.white,child: Text('Login'),
                  onPressed:login),
            ],)
              ,),)
         ),
    );
  }
}

wprowadź opis obrazu tutaj


2
Dodaj trochę więcej kontekstu do swojej odpowiedzi.
Death Waltz

10

Przyjąłem następujące podejście, które używa prostego widżetu wskaźnika postępu modalnego, który zawija wszystko, co chcesz zrobić modalne podczas wywołania asynchronicznego.

Przykład w pakiecie dotyczy również sposobu obsługi walidacji formularza podczas wykonywania wywołań asynchronicznych w celu sprawdzenia poprawności formularza ( szczegóły tego problemu można znaleźć w flutter / Issues / 9688 ). Na przykład bez opuszczania formularza ta asynchroniczna metoda sprawdzania poprawności formularza może służyć do sprawdzania poprawności nowej nazwy użytkownika względem istniejących nazw w bazie danych podczas rejestracji.

https://pub.dartlang.org/packages/modal_progress_hud

Oto demo przykładu dostarczonego z pakietem (z kodem źródłowym):

walidacja formularza asynchronicznego ze wskaźnikiem postępu modalnego

Przykład można dostosować do innych zachowań wskaźnika postępu modalnego (takich jak różne animacje, dodatkowy tekst w trybie modalnym itp.).


2

To jest moje rozwiązanie ze stosem

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';

final themeColor = new Color(0xfff5a623);
final primaryColor = new Color(0xff203152);
final greyColor = new Color(0xffaeaeae);
final greyColor2 = new Color(0xffE8E8E8);

class LoadindScreen extends StatefulWidget {
  LoadindScreen({Key key, this.title}) : super(key: key);
  final String title;
  @override
  LoginScreenState createState() => new LoginScreenState();
}

class LoginScreenState extends State<LoadindScreen> {
  SharedPreferences prefs;

  bool isLoading = false;

  Future<Null> handleSignIn() async {
    setState(() {
      isLoading = true;
    });
    prefs = await SharedPreferences.getInstance();
    var isLoadingFuture = Future.delayed(const Duration(seconds: 3), () {
      return false;
    });
    isLoadingFuture.then((response) {
      setState(() {
        isLoading = response;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(
            widget.title,
            style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
          ),
          centerTitle: true,
        ),
        body: Stack(
          children: <Widget>[
            Center(
              child: FlatButton(
                  onPressed: handleSignIn,
                  child: Text(
                    'SIGN IN WITH GOOGLE',
                    style: TextStyle(fontSize: 16.0),
                  ),
                  color: Color(0xffdd4b39),
                  highlightColor: Color(0xffff7f7f),
                  splashColor: Colors.transparent,
                  textColor: Colors.white,
                  padding: EdgeInsets.fromLTRB(30.0, 15.0, 30.0, 15.0)),
            ),

            // Loading
            Positioned(
              child: isLoading
                  ? Container(
                      child: Center(
                        child: CircularProgressIndicator(
                          valueColor: AlwaysStoppedAnimation<Color>(themeColor),
                        ),
                      ),
                      color: Colors.white.withOpacity(0.8),
                    )
                  : Container(),
            ),
          ],
        ));
  }
}

2

Proponuję użyć tej wtyczki flutter_easyloading

flutter_easyloading jest przejrzystym i lekkim widgetem ładowania aplikacji Flutter, łatwym w użyciu bez kontekstu, obsługuje iOS i Android

Dodaj to do pubspec.yamlpliku pakietu :

dependencies:
  flutter_easyloading: ^2.0.0

Teraz w swoim kodzie Dart możesz użyć:

import 'package:flutter_easyloading/flutter_easyloading.dart';

Aby użyć First, zainicjuj FlutterEasyLoadingw MaterialApp/CupertinoApp

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import './custom_animation.dart';

import './test.dart';

void main() {
  runApp(MyApp());
  configLoading();
}

void configLoading() {
  EasyLoading.instance
    ..displayDuration = const Duration(milliseconds: 2000)
    ..indicatorType = EasyLoadingIndicatorType.fadingCircle
    ..loadingStyle = EasyLoadingStyle.dark
    ..indicatorSize = 45.0
    ..radius = 10.0
    ..progressColor = Colors.yellow
    ..backgroundColor = Colors.green
    ..indicatorColor = Colors.yellow
    ..textColor = Colors.yellow
    ..maskColor = Colors.blue.withOpacity(0.5)
    ..userInteractions = true
    ..customAnimation = CustomAnimation();
}

Następnie użyj zgodnie ze swoimi wymaganiami

import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:dio/dio.dart';

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  @override
  void initState() {
    super.initState();
    // EasyLoading.show();
  }

  @override
  void deactivate() {
    EasyLoading.dismiss();
    super.deactivate();
  }

  void loadData() async {
    try {
      EasyLoading.show();
      Response response = await Dio().get('https://github.com');
      print(response);
      EasyLoading.dismiss();
    } catch (e) {
      EasyLoading.showError(e.toString());
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter EasyLoading'),
      ),
      body: Center(
        child: FlatButton(
          textColor: Colors.blue,
          child: Text('loadData'),
          onPressed: () {
            loadData();
            // await Future.delayed(Duration(seconds: 2));
            // EasyLoading.show(status: 'loading...');
            // await Future.delayed(Duration(seconds: 5));
            // EasyLoading.dismiss();
          },
        ),
      ),
    );
  }
}

wprowadź opis obrazu tutaj


Gdzie jest klasa animacji niestandardowej? Czy musimy to uwzględnić.
Nayas Subramanian

Nie, nie musisz tego robić, a jeśli chcesz, wejdź na: github.com/huangjianke/flutter_easyloading/blob/develop/example/…
Paresh Mangukiya

1

Zamiast tego możesz użyć widgetu FutureBuilder. To wymaga argumentu, który musi być przyszłością. Następnie możesz użyć migawki, która jest aktualnym stanem wywołania asynchronicznego podczas logowania, po jego zakończeniu stan funkcji asynchronicznej zostanie zaktualizowany, a przyszły konstruktor odbuduje się, więc możesz poprosić o nowe stan.

FutureBuilder(
  future:  myFutureFunction(),
  builder: (context, AsyncSnapshot<List<item>> snapshot) {
    if (!snapshot.hasData) {
      return Center(
        child: CircularProgressIndicator(),
      );
    } else {
     //Send the user to the next page.
  },
);

Tutaj masz przykład, jak budować przyszłość

Future<void> myFutureFunction() async{
 await callToApi();}

1

Możesz to zrobić dla środkowego przezroczystego wskaźnika postępu

Future<Null> _submitDialog(BuildContext context) async {
  return await showDialog<Null>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return SimpleDialog(
          elevation: 0.0,
          backgroundColor: Colors.transparent,
          children: <Widget>[
            Center(
              child: CircularProgressIndicator(),
            )
          ],
        );
      });
}

0
class Loader extends StatefulWidget {
      @override
      State createState() => LoaderState();
    }

    class LoaderState extends State<Loader> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> animation;

      @override
      void initState() {
        super.initState();
        controller = AnimationController(
            duration: Duration(milliseconds: 1200), vsync: this);
        animation = CurvedAnimation(parent: controller, curve: Curves.elasticOut);
        animation.addListener(() {
          this.setState(() {});
        });
        animation.addStatusListener((AnimationStatus status) {});
        controller.repeat();
      }

      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }

      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              color: Colors.blue,
              height: 3.0,
              width: animation.value * 100.0,
            ),
            Padding(
              padding: EdgeInsets.only(bottom: 5.0),
            ),
            Container(
              color: Colors.blue[300],
              height: 3.0,
              width: animation.value * 75.0,
            ),
            Padding(
              padding: EdgeInsets.only(bottom: 5.0),
            ),
            Container(
              color: Colors.blue,
              height: 3.0,
              width: animation.value * 50.0,
            )
          ],
        );
      }
    }


    Expanded(
                        child: Padding(
                          padding:
                              EdgeInsets.only(left: 20.0, right: 5.0, top:20.0),
                          child: GestureDetector(
                            onTap: () {
                              Navigator.push(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) => FirstScreen()));
                            },
                            child: Container(
                                alignment: Alignment.center,
                                height: 45.0,
                                decoration: BoxDecoration(
                                    color: Color(0xFF1976D2),
                                    borderRadius: BorderRadius.circular(9.0)),
                                child: Text('Login',
                                    style: TextStyle(
                                        fontSize: 20.0, color: Colors.white))),
                          ),
                        ),
                      ),

Jak mogę połączyć klasę, która tworzy wskaźnik ładowania z moim przyciskiem, tak aby po naciśnięciu wskaźnika włączał się i przewijał do następnej strony?
Max Zubko

0
{
isloading? progressIos:Container()

progressIos(int i) {
    return Container(
        color: i == 1
            ? AppColors.liteBlack
            : i == 2 ? AppColors.darkBlack : i == 3 ? AppColors.pinkBtn : '',
        child: Center(child: CupertinoActivityIndicator()));
  }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.