Flutter: ожидание функции перед сборкой - PullRequest
1 голос
/ 10 июля 2020

Я создаю страницу профиля в своем приложении для пользователей, которые могут входить в систему и выходить из нее, используя свой собственный номер учетной записи и код доступа. Я использую SharedPreference для хранения данных на локальных устройствах, включая логическое значение logined, для которого будет установлено значение true после входа пользователей в систему (по умолчанию - false). Вот и проблема. Я хочу показывать пользователям их собственную страницу профиля каждый раз, когда они переходят на эту страницу, без повторного перехода на страницу входа после входа в систему. Итак, прежде чем я создам эту страницу, я должен проверить, является ли переменная 'logined' на 'true' или «ложь». Если это правда, перейдите на страницу профиля. Если false, показать страницу входа. Но на самом деле страница входа в систему всегда отображается до того, как функция LoginedCheck (которая используется для проверки переменной «зарегистрирован» и навигации) выполнит свою работу. Откроется страница входа в систему, а затем быстро перейдет на страницу профиля. Я пробовал использовать «задержку», чтобы дождаться LoginedCheck (), но экран станет черным до создания страницы профиля. Есть идеи по решению проблемы? Например, спасибо.

Метод сборки:

Widget build(BuildContext context) {
    LoginedCheck();
    return Scaffold(
      resizeToAvoidBottomPadding: false,
      body: Stack(
        children: <Widget>[
          Container(
            height: double.infinity,
            width: double.infinity,
            decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Color(0xFF73AEF5),
                    Color(0xFF61A4F1),
                    Color(0xFF478DE0),
                    Color(0xFF398AE5),
                  ],
                  stops: [0.1,0.4,0.7,0.9],
                )),
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  SizedBox(
                    height: 10,
                  ),
                  Icon(
                    Icons.account_circle,
                    size: 150.0,
                  ),
                  SizedBox(height: 30),
                  Container(
                    width: 300,
                    child: Theme(
                        data: ThemeData(
                          primaryColor: Colors.white,
                          primaryColorDark: Colors.yellowAccent,
                        ),
                        child: TextField(
                          controller: _LtextFieldAccount,
                          decoration: InputDecoration(
                              border: OutlineInputBorder(),
                              hintText: '請輸入帳號',
                              prefixIcon: const Icon(Icons.person)),
                        )),
                  ),
                  SizedBox(height: 20),
                  Container(
                    width: 300,
                    child: Theme(
                        data: ThemeData(
                          primaryColor: Colors.white,
                          primaryColorDark: Colors.yellowAccent,
                        ),
                        child: TextField(
                          controller: _LtextFieldID,
                          decoration: InputDecoration(
                              border: OutlineInputBorder(),
                              hintText: '請輸入密碼',
                              prefixIcon: const Icon(Icons.lock)),
                        )),
                  ),
                  SizedBox(height: 30),
                  RaisedButton(
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(25.0)),
                    elevation: 4.0,
                    color: Colors.white,
                    child: Container(
                      padding: EdgeInsets.only(
                          left: 10,right: 10,top: 10,bottom: 10),
                      child: Text(
                        '登入',
                        style:
                        TextStyle(fontSize: 25,color: Colors.blueAccent),
                      ),
                    ),
                    onPressed: Login,
                  ),
                  SizedBox(height: 20),
                  RaisedButton(
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(25.0)),
                      elevation: 4.0,
                      color: Colors.white,
                      child: Container(
                        padding: EdgeInsets.only(
                            left: 10,right: 10,top: 10,bottom: 10),
                        child: Text(
                          '新用戶註冊',
                          style:
                          TextStyle(fontSize: 25,color: Colors.blueAccent),
                        ),
                      ),
                      onPressed: (){
                        Navigator.of(context).push(MaterialPageRoute(
                            builder: (context) => RegisterPage()));
                      })
                ],
              ),
            ),
          ),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: onTabTapped,
        currentIndex: _currentIndex, //thiswillbesetwhenanewtabistapped
        items: [
          new BottomNavigationBarItem(
            icon: new Icon(Icons.school),
            title: new Text('大學'),
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.directions_subway),
            title: new Text('交通'),
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.person),
            title: new Text('個人'),
          )
        ],
      ),
    );
  }

Функция LoginedCheck ():

Future LoginedCheck() async{
    SharedPreferences prefs = await SharedPreferences.getInstance();

    bool logined = prefs.getBool(_StorageLogined) ?? false;
    int GetUserNum = prefs.getInt(_StorageUserNum) ?? 0;

    if(logined == true) {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (context) => ShowProfile(UserNum: GetUserNum,)));
    }
  }

Ответы [ 3 ]

0 голосов
/ 10 июля 2020

Вы можете вызвать функцию LoginCheck в методе жизненного цикла initState. Таким образом, функция будет выполнена до метода build. см. ниже ниже:

  bool logined;
  int GetUserNum;
  initState(){
    super.initState();

    LoginedCheck().then((results){  
        setState((){
          logined = results[0];
          GetUserNum = results[1];
        });

      if(logined==true)Navigator.of(context).push(
      MaterialPageRoute( builder: (context) => ShowProfile(UserNum: GetUserNum))
      );
    });


  }  



  Widget build(BuildContext context) {

  return Scaffold(
    resizeToAvoidBottomPadding: false,
    body: logined==false?Stack( //if logined is not true we display the login page else we show a loader while we naviagate to the user's page
      children: <Widget>[
        Container(
          height: double.infinity,
          width: double.infinity,
          decoration: BoxDecoration(
              gradient: LinearGradient(
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
                colors: [
                  Color(0xFF73AEF5),
                  Color(0xFF61A4F1),
                  Color(0xFF478DE0),
                  Color(0xFF398AE5),
                ],
                stops: [0.1,0.4,0.7,0.9],
              )),
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SizedBox(
                  height: 10,
                ),
                Icon(
                  Icons.account_circle,
                  size: 150.0,
                ),
                SizedBox(height: 30),
                Container(
                  width: 300,
                  child: Theme(
                      data: ThemeData(
                        primaryColor: Colors.white,
                        primaryColorDark: Colors.yellowAccent,
                      ),
                      child: TextField(
                        controller: _LtextFieldAccount,
                        decoration: InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: '請輸入帳號',
                            prefixIcon: const Icon(Icons.person)),
                      )),
                ),
                SizedBox(height: 20),
                Container(
                  width: 300,
                  child: Theme(
                      data: ThemeData(
                        primaryColor: Colors.white,
                        primaryColorDark: Colors.yellowAccent,
                      ),
                      child: TextField(
                        controller: _LtextFieldID,
                        decoration: InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: '請輸入密碼',
                            prefixIcon: const Icon(Icons.lock)),
                      )),
                ),
                SizedBox(height: 30),
                RaisedButton(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(25.0)),
                  elevation: 4.0,
                  color: Colors.white,
                  child: Container(
                    padding: EdgeInsets.only(
                        left: 10,right: 10,top: 10,bottom: 10),
                    child: Text(
                      '登入',
                      style:
                      TextStyle(fontSize: 25,color: Colors.blueAccent),
                    ),
                  ),
                  onPressed: Login,
                ),
                SizedBox(height: 20),
                RaisedButton(
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(25.0)),
                    elevation: 4.0,
                    color: Colors.white,
                    child: Container(
                      padding: EdgeInsets.only(
                          left: 10,right: 10,top: 10,bottom: 10),
                      child: Text(
                        '新用戶註冊',
                        style:
                        TextStyle(fontSize: 25,color: Colors.blueAccent),
                      ),
                    ),
                    onPressed: (){
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (context) => RegisterPage()));
                    })
              ],
            ),
          ),
        ),
      ],
    ):Center(child:CircularProgressIndicator()),
    bottomNavigationBar: BottomNavigationBar(
      onTap: onTabTapped,
      currentIndex: _currentIndex, //thiswillbesetwhenanewtabistapped
      items: [
        new BottomNavigationBarItem(
          icon: new Icon(Icons.school),
          title: new Text('大學'),
        ),
        new BottomNavigationBarItem(
          icon: new Icon(Icons.directions_subway),
          title: new Text('交通'),
        ),
        new BottomNavigationBarItem(
          icon: new Icon(Icons.person),
          title: new Text('個人'),
        )
      ],
    ),
  );
}
0 голосов
/ 10 июля 2020

Ваш заголовок действительно не соответствует вашему вопросу. Фактически, вы в основном задали 3 вопроса:

Как ожидать функцию до / в build? : Нет, build можно вызывать несколько раз, это На самом деле, вы не можете контролировать, когда и как он вызывается, и вам не следует делать предположений об этом. Вместо этого вы можете использовать FutureBuilder для создания 2 разных виджетов, в зависимости от того, решено ли будущее или нет.

Как автоматически перемещаться при вводе страницы? : активировать метод для проверки и перемещаться по initState, но вы не можете предотвратить создание / отображение первой страницы (поскольку вы сначала перешли на эту страницу).

Как сделать условную навигацию? : Сначала вы дождитесь будущего, а затем перейдите.

Для вашего варианта использования : вы хотите выполнить условную навигацию, поэтому, прежде чем перейти на страницу входа (предположительно, первую страницу в вашем приложении), предоставить что-то вроде страницы spla sh, где вы проверяете, вошел ли пользователь в систему. И после решения будущего вы выполняете навигацию либо к профилю, либо к экрану входа. Вы можете обернуть это функцией, чтобы повторно использовать эту условную навигацию на других страницах, где вы хотите попасть либо на страницу входа в систему, либо на страницу профиля.

0 голосов
/ 10 июля 2020

Вы можете скопировать и вставить полный код ниже
Вы можете получить logined в main() и выполнить навигацию в initialRoute
фрагмент кода

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  SharedPreferences prefs = await SharedPreferences.getInstance();

  logined = prefs.getBool(_StorageLogined) ?? false;
  GetUserNum = prefs.getInt(_StorageUserNum) ?? 0;

  runApp(MyApp());
}
...
initialRoute: logined == false ? "/login" : "/profile",
      routes: {
        '/profile': (context) => ShowProfile(
              title: "demo",
            ),
        "/login": (context) => Login(),
      },

полный код

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

bool logined;
int GetUserNum;
String _StorageLogined = "Logined";
String _StorageUserNum = "UserNum";

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  SharedPreferences prefs = await SharedPreferences.getInstance();

  logined = prefs.getBool(_StorageLogined) ?? false;
  GetUserNum = prefs.getInt(_StorageUserNum) ?? 0;

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: logined == false ? "/login" : "/profile",
      routes: {
        '/profile': (context) => ShowProfile(
              title: "demo",
            ),
        "/login": (context) => Login(),
      },
    );
  }
}

class Login extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Login "),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Login Page',
            ),
          ],
        ),
      ),
    );
  }
}

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

  final String title;

  @override
  _ShowProfileState createState() => _ShowProfileState();
}

class _ShowProfileState extends State<ShowProfile> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
...