You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中基于登录状态控制Drawer内ListView中登录/登出按钮显隐

Solution for Dynamic Login/Logout Buttons in Drawer ListView

Hey there! Let's get this sorted out. The key here is to dynamically build your ListView items based on the login state from SharedPreferences, and place the buttons in the correct position (top for login, bottom for logout). Here's how to do it:

Step 1: Handle Async SharedPreferences Fetch

Since accessing SharedPreferences is asynchronous, we'll use a FutureBuilder to wait for the userId before rendering the drawer content. This ensures we don't render anything until we know the login state.

Step 2: Build Dynamic List Items

We'll create a list of widgets for the ListView. If the user is not logged in (userId is null), we add the Login button at the start of the list. If they are logged in, we add the Logout button at the end.

Full Working Code Example

class YourDrawerWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: FutureBuilder<SharedPreferences>(
        future: SharedPreferences.getInstance(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            // Show loading while waiting for SharedPreferences
            return Center(child: CircularProgressIndicator());
          }

          final userId = snapshot.data!.getInt('userId');
          // Your base drawer items (other links/options in the drawer)
          final List<Widget> drawerItems = [
            // Add your regular drawer items here, e.g.:
            ListTile(
              leading: Icon(Icons.home),
              title: Text('Home'),
              onTap: () => Navigator.pop(context),
            ),
            ListTile(
              leading: Icon(Icons.settings),
              title: Text('Settings'),
              onTap: () {
                Navigator.pop(context);
                // Navigate to settings
              },
            ),
            // Add more items as needed
          ];

          // Insert login/logout button based on state
          if (userId == null) {
            // Not logged in: add Login button at the TOP
            drawerItems.insert(0, _buildLoginButton(context));
          } else {
            // Logged in: add Logout button at the END
            drawerItems.add(_buildLogoutButton(context));
          }

          return ListView(
            padding: EdgeInsets.zero,
            children: drawerItems,
          );
        },
      ),
    );
  }

  // Reusable Login button widget
  Widget _buildLoginButton(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(top: 10, bottom: 10),
      child: InkWell(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => LoginandSignupScreen()),
          );
        },
        child: Row(
          children: <Widget>[
            Expanded(flex: 2, child: Icon(Icons.card_travel)),
            Expanded(
              flex: 10,
              child: Text('Login', style: TextStyle(fontSize: 15)),
            ),
          ],
        ),
      ),
    );
  }

  // Reusable Logout button widget
  Widget _buildLogoutButton(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(top: 10, bottom: 10),
      child: InkWell(
        onTap: () {
          Provider.of<Auth>(context, listen: false).logout();
          // After logout, navigate back to home and refresh the drawer state
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(builder: (context) => HomeScreen()),
          );
        },
        child: Row(
          children: <Widget>[
            Expanded(flex: 2, child: Icon(Icons.card_travel)),
            Expanded(
              flex: 10,
              child: Text('Logout', style: TextStyle(fontSize: 15)),
            ),
          ],
        ),
      ),
    );
  }
}

Key Notes:

  • FutureBuilder: Ensures we wait for SharedPreferences to load before deciding which button to show.
  • Reusable Widgets: Extracting login/logout buttons into separate methods keeps the code clean and easy to maintain.
  • State Refresh: After logout, using Navigator.pushReplacement will rebuild the HomeScreen (and its drawer) so the login button appears immediately without needing manual state updates.

Bonus: Using Provider for Smarter State Management

Since you're already using Provider for Auth, you could listen to the Auth state directly instead of relying on SharedPreferences. This would make the state update automatically when the user logs in/out, without needing to push replacement routes. For example:

// In your drawer widget
Consumer<Auth>(
  builder: (context, auth, child) {
    final userId = auth.userId; // Assume your Auth provider exposes userId
    // Build drawer items based on auth.userId here
  },
)

This way, when auth.logout() is called, the Consumer will rebuild automatically, updating the drawer buttons instantly.

内容的提问来源于stack exchange,提问作者chetan suri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:07:43