首页 > 解决方案 > 底部导航栏在登录时消失,但是当我转到另一个页面并返回时返回?

问题描述

我正在尝试创建一个应用程序,该应用程序将向用户显示包含产品的通用主页,并为他们提供导航到帐户页面的选项,如果他们未登录,他们将显示登录/注册页面,或者如果他们已登录,他们将显示他们的个人资料。

我已经设法让登录/注销部分正常工作,但是当我登录并导航到个人资料页面时,我的底部导航栏消失了。但是,当我导航到另一个页面并返回时,它会重新出现。

这是我的 home.dart 文件,它控制我的应用程序的导航:

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  PageController _pageController = PageController();
  List<Widget> _screens = [HomePage(), InboxPage(), AccountController()];


  int _selectedIndex = 0;

  void _onPageChanged(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  void _onItemTapped(int selectedIndex) {
    _pageController.jumpToPage(selectedIndex);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        controller: _pageController,
        children: _screens,
        onPageChanged: _onPageChanged,
        physics: NeverScrollableScrollPhysics(),
      ),
      bottomNavigationBar: BottomNavigationBar(onTap: _onItemTapped, items: [
        BottomNavigationBarItem(
          icon: Icon(
            Icons.home,
            color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
          ),
          title: Text(
            'Home',
            style: TextStyle(
              color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
            ),
          ),
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Icons.email,
            color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
          ),
          title: Text(
            'Inbox',
            style: TextStyle(
              color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
            ),
          ),
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Icons.account_circle,
            color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
          ),
          title: Text(
            'Account',
            style: TextStyle(
              color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
            ),
          ),
        ),
      ]),
    );
  }
}

我的 accountcontroller.dart 代码有助于确定用户是否登录:

class AccountController extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AuthService auth = Provider.of(context).auth;
    return StreamBuilder(
        stream: auth.onAuthStateChanged,
        builder: (context, AsyncSnapshot<String> snapshot) {
          if (snapshot.connectionState == ConnectionState.active) {
            final bool signedIn = snapshot.hasData;
            return signedIn ? ProfileView() : SignUpPage();
          }
          return CircularProgressIndicator();
        });
  }
}

我的 profileview.dart:

class ProfileView extends StatefulWidget {

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

class _ProfileViewState extends State<ProfileView> {


  @override
  Widget build(BuildContext context) {
    return
      Scaffold(
        appBar: PreferredSize(
            preferredSize: const Size.fromHeight(80),
            child: MainAppBar(
              text: 'Account',
            )),
        body: SingleChildScrollView(
        child: Column(
        children: <Widget>[
          Text('Account Page'),
          showSignOut(context),
          goToHomepage(context),
        ],
        ),
    ),
      );
  }
}

Widget showSignOut(context) {
  return RaisedButton(
      child: Text('Sign Out'),
      onPressed: () async {
        try {
          await Provider.of(context).auth.signOut();
          Navigator.pushNamed(context, '/homepage');
          print('Signed Out');
        } catch (e) {
          print(e);
        }
      });
}

Widget goToHomepage(context) {
  return RaisedButton(
      child: Text('Go to homepage'),
      onPressed: () async {
        try {
          Navigator.pushNamed(context, '/homepage');
        } catch (e) {
          print(e);
        }
      });
}

最后是我的 signup.dart 文件,其中包含我的注册/登录代码:

enum AuthFormType { signIn, signUp }

class SignUpPage extends StatefulWidget {
  final AuthFormType authFormType;

  SignUpPage({Key key, this.authFormType}) : super(key: key);

  @override
  _SignUpPageState createState() =>
      _SignUpPageState(authFormType: this.authFormType);
}

class _SignUpPageState extends State<SignUpPage> {
  AuthFormType authFormType;

  _SignUpPageState({this.authFormType});

  final formKey = GlobalKey<FormState>();
  String _firstName,
      _lastName,
      _email,
      _confirmEmail,
      _password,
      _confirmPassword,
      _dateOfBirth;

  bool validate() {
    final form = formKey.currentState;
    form.save();
    if (form.validate()) {
      form.save();
      print('true');
      return true;
    } else {
      print('false');
      return false;
    }
  }

  void switchFormState(String state) {
    formKey.currentState.reset();
    if (state == 'signIn') {
      setState(() {
        authFormType = AuthFormType.signIn;
      });
    } else {
      setState(() {
        authFormType = AuthFormType.signUp;
      });
    }
  }

  void submit() async {
    final CollectionReference userCollection =
        Firestore.instance.collection('UserData');

    if (validate()) {
      try {
        final auth = Provider.of(context).auth;
        if (authFormType == AuthFormType.signIn) {
          String uid = await auth.signInWithEmailAndPassword(_email, _password);
          print("Signed In with ID $uid");
          Navigator.of(context).pushReplacementNamed('/home');
        } else {
          String uid = await auth.createUserWithEmailAndPassword(
            _email,
            _password,
          );
          userCollection.document(uid).setData({
            'First Name': _firstName,
            'Last Name': _lastName,
            'Date of Birth': _dateOfBirth
          });
          print("Signed up with New ID $uid");
          Navigator.of(context).pushReplacementNamed('/home');
        }
      } catch (e) {
        print(e);
      }
    }
  }

  DateTime selectedDate = DateTime.now();
  TextEditingController _date = new TextEditingController();

  Future<Null> _selectDate(BuildContext context) async {
    DateFormat formatter =
        DateFormat('dd/MM/yyyy'); //specifies day/month/year format

    final DateTime picked = await showDatePicker(


        context: context,
        initialDate: selectedDate,
        firstDate: DateTime(1901, 1),
        builder: (BuildContext context, Widget child) {
          return Theme(
            data: ThemeData.light().copyWith(
              colorScheme: ColorScheme.light(
                primary: kPrimaryColor,
                onPrimary: Colors.black,),
              buttonTheme: ButtonThemeData(
                colorScheme: Theme.of(context)
                    .colorScheme
                    .copyWith(primary: Colors.black),
              ),
            ),
            child: child,
          );
        },
        lastDate: DateTime(2100));

    if (picked != null && picked != selectedDate)
      setState(() {
        selectedDate = picked;
        _date.value = TextEditingValue(
            text: formatter.format(
                picked)); //Use formatter to format selected date and assign to text field
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: PreferredSize(
            preferredSize: const Size.fromHeight(80),
            child: MainAppBar(
              text: buildAppBarText(),
            )),
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(12.0),
            child: Center(
              child: Container(
                child: Column(
                  children: <Widget>[
                    Align(
                      child: Text(buildTitleText(), style: AppBarTextStyle),
                    ),
                    Container(
                      padding: EdgeInsets.only(top: 10),
                    ),
                    Padding(
                      padding: const EdgeInsets.all(20.0),
                      child: Form(
                          key: formKey,
                          child: Column(
                            children: buildInputs() + buildSwitchText(),
                          )),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ));
  }

  buildHeaderText() {
    String _headerText;
    if (authFormType == AuthFormType.signUp) {
      _headerText = "Don't have an account?";
    } else {
      _headerText = "Already have an account?";
    }
    return _headerText;
  }

  List<Widget> buildInputs() {
    List<Widget> textFields = [];

    DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");

    if (authFormType == AuthFormType.signIn) {
      textFields.add(TextFormField(
          style: TextStyle(
            fontSize: 12.0,
          ),
          decoration: buildSignUpInputDecoration('Email'),
          validator: SignInEmailValidator.validate,
          onSaved: (value) => _email = value.trim()));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(
        TextFormField(
          style: TextStyle(
            fontSize: 12.0,
          ),
          decoration: buildSignUpInputDecoration('Password'),
          obscureText: true,
          validator: SignInPasswordValidator.validate,
          onSaved: (value) => _password = value.trim(),
        ),
      );
    } else {
      textFields.clear();
      //if we're in the sign up state, add name
      // add email & password
      textFields.add(TextFormField(
        style: TextStyle(
          fontSize: 12.0,
        ),
        decoration: buildSignUpInputDecoration('First Name'),
        validator: NameValidator.validate,
        onSaved: (value) => _firstName = value,
      ));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(TextFormField(
        style: TextStyle(
          fontSize: 12.0,
        ),
        decoration: buildSignUpInputDecoration('Last Name'),
        onSaved: (value) => _lastName = value,
        validator: NameValidator.validate,
      ));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(TextFormField(
        style: TextStyle(
          fontSize: 12.0,
        ),
        decoration: buildSignUpInputDecoration('Email Address'),
        onSaved: (value) => _email = value.trim(),
        validator: SignInEmailValidator.validate,
      ));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(TextFormField(
        style: TextStyle(
          fontSize: 12.0,
        ),
        decoration: buildSignUpInputDecoration('Confirm Email Address'),
        onSaved: (value) => _confirmEmail = value,
        validator: (confirmation) {
          return confirmation == _email
              ? null
              : "Confirm Email Address should match email address";
        },
      ));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(TextFormField(
        style: TextStyle(
          fontSize: 12.0,
        ),
        decoration: buildSignUpInputDecoration('Password'),
        obscureText: true,
        onSaved: (value) => _password = value,
      ));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(TextFormField(
          style: TextStyle(
            fontSize: 12.0,
          ),
          decoration: buildSignUpInputDecoration('Confirm Password'),
          onSaved: (value) => _confirmPassword = value,
          validator: (confirmation) {
            return confirmation == _password
                ? null
                : "Confirm Password should match password";
          }));
      textFields.add(SizedBox(
        height: 15,
      ));
      textFields.add(GestureDetector(
        onTap: () => _selectDate(context),
        child: AbsorbPointer(
          child: TextFormField(
            style: TextStyle(fontSize: 12.0),
            controller: _date,
            keyboardType: TextInputType.datetime,
            decoration: InputDecoration(
              isDense: true,
              fillColor: Colors.white,
              hintText: 'Date of Birth',
              filled: true,
              enabledBorder: OutlineInputBorder(
                borderSide: BorderSide(width: 0.0),
              ),
              contentPadding:
                  const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
            ),
            onSaved: (value) => _dateOfBirth = value,
          ),
        ),
      ));

      textFields.add(SizedBox(
        height: 15,
      ));
    }
    return textFields;
  }

  List<Widget> buildSwitchText() {
    String _switchButtonTextPart1, _switchButtonTextPart2, _newFormState;

    if (authFormType == AuthFormType.signIn) {
      _switchButtonTextPart1 = "Haven't got an account? ";
      _switchButtonTextPart2 = 'Sign Up';
      _newFormState = 'signUp';
    } else {
      _switchButtonTextPart1 = 'Already have an account? ';
      _switchButtonTextPart2 = 'Sign In';
      _newFormState = 'signIn';
    }
    return [
      SizedBox(height: 5.0),
      Container(
        width: MediaQuery.of(context).size.height * 0.7,
        child: RaisedButton(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(5.0),
            ),
            color: kPrimaryColor,
            textColor: Colors.black,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                buildTitleText(),
                style: TextStyle(fontFamily: FontNameDefault, fontSize: 15.0),
              ),
            ),
            onPressed: submit),
      ),
      SizedBox(
        height: 5.0,
      ),
      RichText(
        text: TextSpan(
            style: TextStyle(
              fontFamily: FontNameDefault,
              color: Colors.black,
              fontSize: 12.0,
            ),
            children: <TextSpan>[
              TextSpan(text: _switchButtonTextPart1),
              TextSpan(
                  text: _switchButtonTextPart2,
                  style: TextStyle(
                      decoration: TextDecoration.underline,
                      color: Colors.black,
                      fontSize: 12.0),
                  recognizer: TapGestureRecognizer()
                    ..onTap = () {
                      switchFormState(_newFormState);
                    })
            ]),
      ),
    ];
  }

  String buildAppBarText() {
    String _switchAppBarHeader;

    if (authFormType == AuthFormType.signIn) {
      _switchAppBarHeader = "Already have an account?";
    } else {
      _switchAppBarHeader = "Don't have an account?";
    }
    return _switchAppBarHeader;
  }

  String buildTitleText() {
    String _switchTextHeader;

    if (authFormType == AuthFormType.signIn) {
      _switchTextHeader = "Sign In";
    } else {
      _switchTextHeader = "Sign Up";
    }
    return _switchTextHeader;
  }
}


InputDecoration buildSignUpInputDecoration(String hint) {
  return InputDecoration(
    isDense: true,
    fillColor: Colors.white,
    hintText: hint,
    filled: true,
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(width: 0.0),
    ),
    contentPadding: const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
  );
}

有任何想法吗?

标签: flutterdart

解决方案


HomePage()、InboxPage() 和 AccountController() 位于您的主页小部件中,其中包含底部导航栏。您的个人资料和注册页面是不同的页面,具有自己的脚手架。您必须创建一个包含每个子页面和导航栏的中央“索引”小部件。


推荐阅读