Flutter:单击 TextField 时,推送的 LoginScreen Widget 正在重建 UI

Flutter: Pushed LoginScreen Widget is rebuilding the UI when clicked the TextField

我有一个导航应用程序屏幕,如果您点击底部导航中的其中一个按钮,它会检查用户是否已登录。如果没有,它会推送登录屏幕。问题是,如果您点击文本字段,则 LoginScreen UI 正在重建。我不知道为什么。我尝试了很多选择,但都没有效果。请帮助我!

NavigationalAppScreen:

class NavigationalAppScreen extends StatefulWidget {
  const NavigationalAppScreen({Key? key}) : super(key: key);

  static String routeName = "/navigational-app";

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

class _NavigationalAppScreenState extends State<NavigationalAppScreen> {
  final _screens = [
    HomePageScreen(),
    SearchPageScreen(),
    EstateCreationPageScreen(),
    ChatPageScreen(),
    UserPageScreen()
  ];

  final List<String> appBarTitles = [
    "homescreen_appbar_text",
    "searchpagescreen_appbar_text",
    "estatecreationscreen_appbar_text",
    "chatpagescreen_appbar_text",
    "userpagescreen_appbar_text",
  ];

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Consumer<NavigationScreenProvider>(
              builder: (context, navigator, _) {
            return LocaleText(appBarTitles[navigator.currentIndex]);
          }),
          actions: [
            IconButton(
              onPressed: () {},
              icon: Icon(
                Icons.favorite_border_outlined,
                size: 30,
                color: Colors.redAccent,
              ),
            )
          ],
        ),
        body: Consumer<NavigationScreenProvider>(
          builder: (context, navigator, _) {
            return IndexedStack(
              index: navigator.currentIndex,
              children: _screens,
            );
          },
        ),
        bottomNavigationBar: _buildBottomNavigation(),
      ),
    );
  }

  Widget _buildBottomNavigation() {
    return BottomNavigationBar(
      showSelectedLabels: false,
      showUnselectedLabels: false,
      type: BottomNavigationBarType.fixed,
      currentIndex: Provider.of<NavigationScreenProvider>(context).currentIndex,
      onTap: (index) {
        if (index != 1) {
          Provider.of<NavigationScreenProvider>(context, listen: false)
              .clearData();
        }
        Provider.of<NavigationScreenProvider>(context, listen: false)
            .changePageIndex(index, () {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => LoginScreen()),
          );
        });
      },
      items: [
        BottomNavigationBarItem(
          icon: Icon(
            Provider.of<NavigationScreenProvider>(context).currentIndex == 0
                ? Icons.home_rounded
                : Icons.home_outlined,
            color: darkPurple,
          ),
          label: "Home",
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Provider.of<NavigationScreenProvider>(context).currentIndex == 1
                ? Icons.search_outlined
                : Icons.search,
            color: darkPurple,
          ),
          label: "Search",
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Provider.of<NavigationScreenProvider>(context).currentIndex == 2
                ? Icons.add_circle_rounded
                : Icons.add_circle_outline_rounded,
            color: darkPurple,
          ),
          label: "Add",
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Provider.of<NavigationScreenProvider>(context).currentIndex == 3
                ? Icons.chat_rounded
                : Icons.chat_outlined,
            color: darkPurple,
          ),
          label: "Chat",
        ),
        BottomNavigationBarItem(
          icon: Icon(
            Provider.of<NavigationScreenProvider>(context).currentIndex == 4
                ? Icons.person_rounded
                : Icons.person_outline_rounded,
            color: darkPurple,
          ),
          label: "User",
        ),
      ],
    );
  }
}

NavigationScreenProvider:

class NavigationScreenProvider extends ChangeNotifier {
  final AuthProvider auth;
  NavigationScreenProvider({required this.auth});

  int _currentIndex = 0;
  List<int> _authRequiredScreens = [2, 3, 4];
  Map<String, dynamic> _data = {};

  int get currentIndex {
    final currentIndex = _currentIndex;
    return currentIndex;
  }

  Map<String, dynamic> get data {
    return {..._data};
  }

  changePageIndex(int index, [Function? callback]) {
    if (!_authRequiredScreens.contains(index) || auth.isAuthenticated) {
      _currentIndex = index;
      notifyListeners();
    } else {
      callback != null ? callback() : null;
    }
    if (index == 0) clearData();
  }

  visitSearchPage(String term) {
    _data = {
      "search_term": term,
    };
    changePageIndex(1);
  }

  clearData() {
    _data = {};
  }
}

登录屏幕:

class LoginScreen extends StatefulWidget {
  const LoginScreen({Key? key}) : super(key: key);

  static String routeName = "/login";

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

class _LoginScreenState extends State<LoginScreen> {
  bool _hidePassword = true;

  FocusNode _phoneFocusNode = FocusNode();
  FocusNode _passwordFocusNode = FocusNode();

  final _phoneController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  void didChangeDependencies() {
    // _phoneFocusNode.addListener(() {
    //   setState(() {});
    // });
    // _passwordFocusNode.addListener(() {
    //   setState(() {});
    // });
    super.didChangeDependencies();
  }

  @override
  void dispose() {
    _phoneFocusNode.dispose();
    _passwordFocusNode.dispose();
    _phoneController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(defaultPadding),
          child: Form(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                LocaleText(
                  "log_in",
                  style: TextStyle(
                    fontSize: 25,
                    color: normalOrange,
                    fontWeight: FontWeight.w700,
                  ),
                ),
                SizedBox(
                  height: 60,
                ),
                TextFormField(
                  focusNode: _phoneFocusNode,
                  controller: _phoneController,
                  inputFormatters: [
                    MaskTextInputFormatter(mask: "+998 ## ### ## ##")
                  ],
                  decoration: InputDecoration(
                    border: InputStyles.inputBorder(),
                    focusedBorder: InputStyles.focusBorder(),
                    prefixIcon: Icon(
                      Icons.phone_outlined,
                    ),
                    hintText: Locales.string(context, "phone_number_hint"),
                  ),
                  keyboardType: TextInputType.number,
                  onFieldSubmitted: (value) {
                    FocusScope.of(context).requestFocus(_passwordFocusNode);
                  },
                ),
                SizedBox(
                  height: 20,
                ),
                TextField(
                  focusNode: _passwordFocusNode,
                  controller: _passwordController,
                  decoration: InputDecoration(
                    border: InputStyles.inputBorder(),
                    focusedBorder: InputStyles.focusBorder(),
                    prefixIcon: Icon(
                      Icons.lock,
                    ),
                    hintText: Locales.string(context, "password_hint"),
                    suffixIcon: IconButton(
                      icon: Icon(
                        Icons.remove_red_eye,
                      ),
                      onPressed: () {
                        setState(() {
                          _hidePassword = !_hidePassword;
                        });
                      },
                    ),
                  ),
                  obscureText: _hidePassword,
                ),
                SizedBox(
                  height: 20,
                ),
                TextLinkButton(
                    Locales.string(context, "forgot_password?"), () {}),
                SizedBox(
                  height: 32,
                ),
                FluidBigButton(Locales.string(context, "log_in"), onPress: () {
                  String phone = _phoneController.text.replaceAll(" ", "");
                  String password = _passwordController.text;
                  Provider.of<AuthProvider>(context, listen: false)
                      .login(phone, password)
                      .then((value) {
                    if (value.containsKey("status") && !value["status"]) {
                      print("You cannot log in!");
                    }
                    Navigator.of(context).pushNamedAndRemoveUntil(
                        NavigationalAppScreen.routeName, (route) => false);
                  });
                }),
                SizedBox(
                  height: 24,
                ),
                Wrap(
                  children: [
                    LocaleText(
                      "no_profile?",
                      style: TextStyle(fontSize: 16),
                    ),
                    SizedBox(width: 10),
                    TextLinkButton(Locales.string(context, "register"), () {
                      Navigator.of(context)
                          .pushReplacementNamed(RegisterScreen.routeName);
                    }),
                  ],
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

在您的 NavigationalAppScreen 中,您将以下代码作为底部导航的一部分:

onTap: (index) {
    if (index != 1) {
      Provider.of<NavigationScreenProvider>(context, listen: false)
          .clearData();
    }
    Provider.of<NavigationScreenProvider>(context, listen: false)
        .changePageIndex(index, () {
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => LoginScreen()),
      );
    });
  },

这将在每次调用 onTap 函数时推送 LoginScreen,因此您看到的行为是正确的。不知道你的代码,也许你可以做你的“我登录了吗?”在 onTap 中测试,只有当结果是 false 时,你才按下 LoginScreen