Как заставить заставку ждать вычислений перед переходом к следующему экрану?

Я делаю экран-заставку на флаттере, и я хочу выполнить некоторые вычисления при отображении экрана-заставки (с работающим круговым индикатором выполнения), и после того, как все вычисления будут выполнены, я хочу запустить Navigator.push () для перехода к дому экран. Проблема в том, что флаттер никогда не ждет вычислений, обходной путь, который я сделал, заключался в добавлении future.delayed () в свой навигатор и ожидании произвольного количества времени, пока все вычисления не будут выполнены.

Код такой: (вычисления - это загружаемые модели)

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) {
      // Do all of this
      final bestModel = Provider.of<BestSellingModel>(context, listen: false);
      final salesModel = Provider.of<SalesModel>(context, listen: false);
      final categoryModel = Provider.of<CategoryModel>(context, listen: false);
      if (bestModel.isLoading) bestModel.getBestSelling();
      if (salesModel.isLoading) salesModel.getSales();
      if (categoryModel.isLoading) categoryModel.getCategories();
      DatabaseHelper.instance.database;
      // And only then navigate to next screen without a pre-established time
      Future.delayed(Duration(seconds: 12), () {
        Navigator.of(context).pushReplacement(
            MaterialPageRoute(builder: (BuildContext context) => MainTabs()));
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;

    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          Container(
            decoration: BoxDecoration(
              gradient: LinearGradient(
                begin: Alignment.topRight,
                end: Alignment.bottomLeft,
                colors: [Color(0xffFBC707), Color(0xffF25D19)],
              ),
            ),
          ),
          Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              Expanded(
                flex: 2,
                child: Container(
                  width: screenSize.width / 1.8,
                  child: Image.asset('assets/images/splash_logo.png'),
                ),
              ),
              Expanded(
                flex: 1,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    // This needs to keep running while the models are being loaded
                    SizedBox(
                      child: CircularProgressIndicator(),
                      height: 64.0,
                      width: 64.0,
                    ),
                  ],
                ),
              )
            ],
          )
        ],
      ),
    );
  }
}

Это пример модели, которую я использовал:

class SalesModel with ChangeNotifier{
  List<Product> products = [];
  bool isLoading = true;

  Future getSales() async {
    products = await WooCommerce().getProductsByCategory(categoryId: 58);
    isLoading = false;
    notifyListeners();
  }
}

Итак, есть ли способ, позволяющий запускать круговой индикатор выполнения на экране-заставке одновременно с загрузкой моделей и переходить на главный экран после загрузки всех моделей?


person Victor Roberti Camolesi    schedule 27.02.2020    source источник
comment
нет, flutter запускает свой код в одном потоке, поэтому вы не можете делать две вещи одновременно - для этого вам нужно использовать Isolates   -  person pskink    schedule 27.02.2020


Ответы (1)


Я делаю нечто подобное с состоянием входа в систему. Мой всплеск прослушивает поток состояний входа в систему.

  void setInProgress(bool value) {
    setState(() {
     _inProgress = value;
    });
  } // of setInProgress

В вашем методе сборки вы можете добавить условия

      if (_inProgress)
        Center(
          child: CircularProgressIndicator(),
        )
      if (!_inProgress)
        Center(

          child: HomeScreenWidget(),
        )

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

person Chris Reynolds    schedule 27.02.2020
comment
Не знаю, почему я никогда раньше не думал об этом. Спасибо! - person Victor Roberti Camolesi; 28.02.2020