如何在颤动中使用底部导航栏时传递列表视图数据?

How to pass listview data while using bottom navigation bar in flutter?

我想将列表视图项的单击数据从一个屏幕传递到另一个屏幕。所有屏幕都有带末端抽屉的底部导航栏。尝试将数据从第二个屏幕传递到详细信息屏幕,但没有成功,因为没有使用导航器。任何人都可以帮助我吗?以下是实现的代码

bottom_nav_bar.dart

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

import 'Utility.dart';
import 'main.dart';

class CustomAnimatedBottomBar extends StatelessWidget {
  CustomAnimatedBottomBar({
    Key? key,
    this.selectedIndex = ScreenType.home,
    this.showElevation = true,
    this.iconSize = 24,
    this.backgroundColor,
    this.itemCornerRadius = 40,
    this.animationDuration = const Duration(milliseconds: 270),
    this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
    required this.items,
    required this.onItemSelected,
    this.curve = Curves.linear,
  })  : assert(items.length >= 2 && items.length <= 5),
        super(key: key);

  final ScreenType selectedIndex;
  final double iconSize;
  final Color? backgroundColor;
  final bool showElevation;
  final Duration animationDuration;
  final List<BottomNavyBarItem> items;
  final ValueChanged<ScreenType> onItemSelected;
  final MainAxisAlignment mainAxisAlignment;
  final double itemCornerRadius;
  final Curve curve;

  @override
  Widget build(BuildContext context) {
    final bgColor = backgroundColor ?? Theme.of(context).bottomAppBarColor;

    return Container(
      decoration: BoxDecoration(
        color: bgColor,
        boxShadow: [
          if (showElevation)
            const BoxShadow(
              color: Colors.black12,
              blurRadius: 2,
            ),
        ],
      ),
      child: SafeArea(
        child: Container(
          width: double.infinity,
          height: kToolbarHeight,
          padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
          child: Row(
            mainAxisAlignment: mainAxisAlignment,
            children: items.map((item) {
              var index = item;
              return GestureDetector(
                onTap: () => onItemSelected(index.screenType),
                child: _ItemWidget(
                  item: item,
                  iconSize: iconSize,
                  isSelected: index.screenType == selectedIndex,
                  backgroundColor: bgColor,
                  itemCornerRadius: itemCornerRadius,
                  animationDuration: animationDuration,
                  curve: curve,
                ),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

class _ItemWidget extends StatelessWidget {
  final double iconSize;
  final bool isSelected;
  final BottomNavyBarItem item;
  final Color backgroundColor;
  final double itemCornerRadius;
  final Duration animationDuration;
  final Curve curve;

  const _ItemWidget({
    Key? key,
    required this.item,
    required this.isSelected,
    required this.backgroundColor,
    required this.animationDuration,
    required this.itemCornerRadius,
    required this.iconSize,
    this.curve = Curves.linear,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Semantics(
      container: true,
      selected: isSelected,
      child: AnimatedContainer(
        width: isSelected ? 130 : 50,
        height: double.maxFinite,
        duration: animationDuration,
        curve: curve,
        decoration: BoxDecoration(
          color:
          isSelected ? item.activeColor.withOpacity(0.2) : backgroundColor,
          borderRadius: BorderRadius.circular(itemCornerRadius),
        ),
        child: Container(
          width: isSelected ? 130 : 50,
          padding: EdgeInsets.symmetric(horizontal: 10),
          child: Row(
            // mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              IconTheme(
                data: IconThemeData(
                  size: iconSize,
                  color: isSelected
                      ? item.activeColor.withOpacity(1)
                      : item.inactiveColor == null
                      ? item.activeColor
                      : item.inactiveColor,
                ),
                child: item.icon,
              ),
              if (isSelected)
                Expanded(
                  child: Container(
                    padding: EdgeInsets.symmetric(horizontal: 4),
                    child: DefaultTextStyle.merge(
                      style: TextStyle(
                        color: item.activeColor,
                        fontWeight: FontWeight.bold,
                      ),
                      maxLines: 1,
                      textAlign: item.textAlign,
                      child: item.title,
                    ),
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}

class BottomNavyBarItem {
  BottomNavyBarItem({
    required this.screenType,
    required this.icon,
    required this.title,
    this.activeColor = Colors.blue,
    this.textAlign,
    this.inactiveColor,
  });

  final ScreenType screenType;
  final Widget icon;
  final Widget title;
  final Color activeColor;
  final Color? inactiveColor;
  final TextAlign? textAlign;
}

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_app/FifthScreen.dart';
import 'package:flutter_app/details_screen.dart';
import 'package:flutter_app/profile_screen.dart';
import 'package:flutter_app/secondPage.dart';

import 'ThirdPage.dart';
import 'Utility.dart';
import 'bottom_nav_bar.dart';
import 'firstpage.dart';
import 'fourthPage.dart';
import 'home_screen.dart';
import 'message_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

enum ScreenType {
  firstScreen,
  secondScreen,
  thirdScreen,
  forthScreen,
  fifthScreen,
  detailsScreen,
  home,
  messages,
  profile
}

class _MyHomePageState extends State<MyHomePage> {
  ScreenType _screenType = ScreenType.home;
  final _inactiveColor = Colors.grey;

  GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: getTitle(_screenType),
      ),
      endDrawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            DrawerHeader(
              child: Text('Drawer Header'),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),
            ListTile(
              title: Text('First Screen'),
              onTap: (){onTabTapped(ScreenType.firstScreen);
              Navigator.of(context).pop();
              },
            ),
            ListTile(
              title: Text('Second Screen'),
              onTap:(){onTabTapped(ScreenType.secondScreen);
              Navigator.of(context).pop();
              },
            ),
            ListTile(
              title: Text('Third Screen'),
              onTap: (){onTabTapped(ScreenType.thirdScreen);
              Navigator.of(context).pop();
              },
            ),
          ],
        ),
      ),
      body: _body(_screenType),
      bottomNavigationBar: _buildBottomBar(),
    );
  }

  Widget _body(ScreenType screenType) {
    switch (screenType) {
      case ScreenType.firstScreen:
        return FirstScreen(
          navigateScreen: (screenType) => onTabTapped(screenType),
        );
      case ScreenType.secondScreen:
        return SecondScreen(
          onClickList: (model){
            setState(() {
              _screenType = ScreenType.detailsScreen;
            });
          },
        );
      case ScreenType.thirdScreen:
        return const ThirdScreen();
      case ScreenType.forthScreen:
        return const ForthScreen();
      case ScreenType.home:
        return const HomeScreen();
      case ScreenType.messages:
        return const MessagesScreen();
      case ScreenType.profile:
        return const ProfileScreen();
      case ScreenType.fifthScreen:
        return const FifthScreen();
      case ScreenType.detailsScreen:
        return DetailsScreen();
    }
  }

  Widget _buildBottomBar() {
    return CustomAnimatedBottomBar(
      backgroundColor: Colors.black,
      selectedIndex: _screenType,
      showElevation: true,
      itemCornerRadius: 24,
      curve: Curves.easeIn,
      onItemSelected: onTabTapped,
      items: <BottomNavyBarItem>[
        BottomNavyBarItem(
          screenType: ScreenType.home,
          icon: Icon(Icons.apps),
          title: Text('Home'),
          activeColor: Colors.green,
          inactiveColor: _inactiveColor,
          textAlign: TextAlign.center,
        ),
        BottomNavyBarItem(
          screenType: ScreenType.messages,
          icon: Icon(Icons.message),
          title: Text('Messages'),
          activeColor: Colors.purpleAccent,
          inactiveColor: _inactiveColor,
          textAlign: TextAlign.center,
        ),
        BottomNavyBarItem(
          screenType: ScreenType.profile,
          icon: Icon(Icons.account_circle_rounded),
          title: Text('Profile'),
          activeColor: Colors.pink,
          inactiveColor: _inactiveColor,
          textAlign: TextAlign.center,
        ),
      ],
    );
  }

  void onTabTapped(ScreenType screenType) {
    if ((_scaffoldKey.currentState ?? ScaffoldState()).isEndDrawerOpen) {
      (_scaffoldKey.currentState ?? ScaffoldState()).openEndDrawer();
    }
    setState(() {
      _screenType = screenType;
    });
  }

  Widget getTitle(ScreenType screenType) {
    switch (screenType) {
      case ScreenType.firstScreen:
        return Text("First Screen");
      case ScreenType.secondScreen:
        return Text("Second Screen");
      case ScreenType.thirdScreen:
        return Text("Third Screen");
      case ScreenType.forthScreen:
        return Row(
          children: [
            IconButton(onPressed: (){
              onTabTapped(ScreenType.firstScreen);
            }, icon: Icon(Icons.arrow_back_ios)),
            Text("Fourth Screen"),
          ],
        );
      case ScreenType.detailsScreen:
        return Text("Details Screen");
      case ScreenType.home:
        return Text("Home");
      case ScreenType.messages:
        return Text("Message");
      case ScreenType.profile:
        return Text("Profile");
      case ScreenType.fifthScreen:
      // TODO: Handle this case.
        return Text("Fifth Sceen");
        break;
    }
  }
}

second_page.dart

import 'package:flutter/material.dart';

typedef OnClickList(Model);

class SecondScreen extends StatefulWidget {
  // final VoidCallback voidCallback;
  final OnClickList onClickList;
  const SecondScreen({Key? key, required this.onClickList}) : super(key: key);

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

class _SecondScreenState extends State<SecondScreen> {
  @override
  Widget build(BuildContext context) {

    List<Model> items = [
      Model(text: "Text 1 to next screen"),
      Model(text: "Text 2 to next screen"),
      Model(text: "Text 3 to next screen"),
    ];
    return Container(
      child: Center(
        child: Column(
          children: [
            Text("Second Screen"),
            ListView.builder(
                itemCount: items.length,
                shrinkWrap: true,scrollDirection: Axis.vertical,
                itemBuilder: (context, index){
                  Model model = items[index];
              return GestureDetector(
                onTap: (){
                  widget.onClickList(model.text);
                },
                child: Card(
                  child: Text("${items[index].text}"),
                ),
              );
            })
          ],
        ),
      ),
    );
  }
}

class Model{
  String text;

  Model({required this.text});
}

details_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_app/secondPage.dart';

class DetailsScreen extends StatefulWidget {
  final Model? model;

  const DetailsScreen({Key? key, this.model}):super(key:key);

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

class _DetailsScreenState extends State<DetailsScreen> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(widget.model!.text.toString()),
      ),
    );
  }
}

first_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';

typedef NavigateScreen(ScreenType);

class FirstScreen extends StatefulWidget {
  const FirstScreen({
    Key? key,
    required this.navigateScreen,
  }) : super(key: key);

  final NavigateScreen navigateScreen;

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

class _FirstScreenState extends State<FirstScreen> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Flex(
          direction: Axis.vertical,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("First Screen"),
            ElevatedButton(
              onPressed: () => widget.navigateScreen(ScreenType.forthScreen),
              child: Text("Go To Forth Screen"),
            ),
            ElevatedButton(
              onPressed: () => widget.navigateScreen(ScreenType.fifthScreen),
              child: Text("Go To Fifth Screen"),
            ),

          ],
        ),
      ),
    );
  }
}

要将数据从第二个屏幕传递到详细信息屏幕:

  1. 在主页状态添加一个变量,可以获取从第二屏幕点击的内容。
class _MyHomePageState extends State<MyHomePage> {
  ScreenType _screenType = ScreenType.home;
  final _inactiveColor = Colors.grey;
  Model? fromSecond;

…….

}
  1. 更改 onClickList 实现和切换大小写。
Widget _body(ScreenType screenType) {
  switch (screenType) {
    case ScreenType.firstScreen:
      return FirstScreen(
        navigateScreen: (screenType) => onTabTapped(screenType),
      );
    case ScreenType.secondScreen:
      return SecondScreen(
        onClickList: (model) {
          fromSecond = model;
          setState(() {
            _screenType = ScreenType.detailsScreen;
          });
        },
      );
……..

…….


case ScreenType.detailsScreen:
  {
    if(fromSecond!=null) {
      return DetailsScreen(model: fromSecond);
    } else {
      return DetailsScreen();
    }
  }
………..

……….


}
  1. 在 SecondScreen 上使手势检测器 return 模型到 onClickList 回调。
…………

…………
return GestureDetector(
  onTap: (){
    widget.onClickList(model);
  },
  child: Card(
    child: Text("${items[index].text}"),
  ),
);
…….

…….