Приложение Flutter аварийно завершает работу при переходе на новый экран при нажатии элемента списка на экране вкладки FancyBottomNavigation. - PullRequest
0 голосов
/ 07 мая 2020

Я перестраиваю приложение, которое уже было разработано с нативным Android с использованием Flutter. Я новичок в Flutter and Dart. Но я остался в своем предыдущем пользовательском интерфейсе с минимальными изменениями. Однако до сих пор с просмотром страниц все было хорошо. Итак, позвольте мне немного объяснить, чем я занимаюсь. B'coz Я не могу найти точную root причину этой проблемы. Во-первых, у меня есть главный экран с ящиком. Внутри этого я реализовал bottomNavigationBar с тремя дочерними экранами вкладок, используя FancyBottomNavigation . Одна вкладка имеет динамический c список, который извлекает данные из PHP скриптов. Эта часть полностью работает без ошибок. Затем я реализовал onTap для каждого списка элементов. Когда пользователь щелкает эти элементы списка, перейдите к третьему экрану, на котором есть другое динамическое c представление списка. Отсюда и ошибка. Третий экран загружен со списком данных без sh. Но исключения выкидываются с этой навигацией. Кроме того, на этом экране есть оставшаяся часть bottomNavigationBar. Затем приложение вылетает при нажатии кнопки возврата. Я уже предпринял несколько попыток решить эту проблему с адресом Inte rnet. * Реализовано PageStorage для вкладок * Добавить удаление для контроллеров * MetirialApp для третьего экрана вместо контейнера, столбца ...

Итак, мне нужно исправить эту проблему сбоя и удалить значок bottomNavigationBar с третьего экрана . Пожалуйста, помогите мне решить эти проблемы и понять причину root.

дочерний экран вкладки - это нормально

thisr screen - оставшаяся часть необходимо удалить

Пожалуйста, обратитесь к исключениям ниже при переходе к третьему экрану.

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building TickerMode(mode: disabled):
setState() or markNeedsBuild() called during build.

This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey<OverlayState>#9de6b]
  state: OverlayState#b259c(entries: [OverlayEntry#ab600(opaque: true; maintainState: false), OverlayEntry#dfdfa(opaque: false; maintainState: true), OverlayEntry#69acb(opaque: true; maintainState: false), OverlayEntry#fcf4a(opaque: false; maintainState: true), OverlayEntry#2439e(opaque: false; maintainState: false)])
The widget which was currently being built when the offending call was made was: TickerMode
  mode: disabled
The relevant error-causing widget was: 
  MaterialApp file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:21:12
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3896:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3911:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1168:14)
#3      _FancyBottomNavigationState._setSelected (package:fancy_bottom_navigation/fancy_bottom_navigation.dart:194:21)
#4      _FancyBottomNavigationState.didChangeDependencies (package:fancy_bottom_navigation/fancy_bottom_navigation.dart:64:5)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (2) Exception caught by widgets library ═══════════════════════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 5158 pos 14: 'oldChild == null || oldChild._debugLifecycleState == _ElementLifecycle.active': is not true.
The relevant error-causing widget was: 
  Scaffold file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:23:13
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (3) Exception caught by widgets library ═══════════════════════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 3037 pos 12: '_debugLifecycleState == _ElementLifecycle.active
        && widget != null
        && newWidget != null
        && newWidget != widget
        && depth != null
        && _active
        && Widget.canUpdate(widget, newWidget)': is not true.
The relevant error-causing widget was: 
  FancyBottomNavigation file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:25:30
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (10800): *JSON DATA*

Пожалуйста, ознакомьтесь с исключениями при нажатии кнопки «Назад» ниже. (Сбой приложения)

════════ (5) Exception caught by widgets library ═══════════════════════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4277 pos 12: 'child == _child': is not true.
The relevant error-causing widget was: 
  MaterialApp file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:21:12
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (6) Exception caught by widgets library ═══════════════════════════════════════════════════
Duplicate GlobalKey detected in widget tree.
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (7) Exception caught by widgets library ═══════════════════════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 5540 pos 12: '_children.contains(child)': is not true.
The relevant error-causing widget was: 
  MaterialApp file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:21:12
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (8) Exception caught by widgets library ═══════════════════════════════════════════════════
The getter 'userGestureInProgress' was called on null.
Receiver: null
Tried calling: userGestureInProgress
The relevant error-causing widget was: 
  MaterialApp file:///D:/DEVELOPMENT/Flutter/quiz_master/lib/screens/home_screen.dart:21:12
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (9) Exception caught by widgets library ═══════════════════════════════════════════════════
Duplicate GlobalKey detected in widget tree.
════════════════════════════════════════════════════════════════════════════════════════════════════

HomeScreen - первый экран с 3 вкладками

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

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

    class _MyHomePageState extends State<MyHomePage> {
  int currentPage = 0;
  final _tabOptions = [ HomeScreen(), LearnHomeScreen(), DiscussionHomeScreen() ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: _tabOptions[currentPage],
        bottomNavigationBar: FancyBottomNavigation(
          circleColor: HexColor("#3DAEDF"),
          inactiveIconColor: HexColor("#3DAEDF"),
          tabs: [
            TabData(iconData: Icons.home, title: "Home"),
            TabData(iconData: Icons.book, title: "Learn"),
            TabData(iconData: Icons.chat, title: "Discussion")
          ],
          onTabChangedListener: (position) {
            setState(() {
              currentPage = position;
            });
          },
        ),
      ),
    );
  }
}

Дочерний экран вкладки - второй экран, который включает просмотр списка

class LearnHomeScreen extends StatefulWidget {
  @override
  _LearnHomeScreenState createState() => _LearnHomeScreenState();
}

class _LearnHomeScreenState extends State<LearnHomeScreen> with TickerProviderStateMixin {

  AnimationController animationController;
  Animation<double> topBarAnimation;
  final ScrollController scrollController = ScrollController();
  double topBarOpacity = 0;
  Future<List<Subject>> subjectsList;
  List<Widget> listViews = <Widget>[];
  String uri;

  @override
  void initState() {
    uri = "xxxxx";
    subjectsList = getSubjects();
    animationController = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);

    topBarAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
        CurvedAnimation(
            parent: animationController,
            curve: Interval(0, 0.5, curve: Curves.fastOutSlowIn)));

    addAllListData();

    scrollController.addListener(() {
      if (scrollController.offset >= 24) {
        if (topBarOpacity != 1.0) {
          setState(() {
            topBarOpacity = 1.0;
          });
        }
      } else if (scrollController.offset <= 24 &&
          scrollController.offset >= 0) {
        if (topBarOpacity != scrollController.offset / 24) {
          setState(() {
            topBarOpacity = scrollController.offset / 24;
          });
        }
      } else if (scrollController.offset <= 0) {
        if (topBarOpacity != 0.0) {
          setState(() {
            topBarOpacity = 0.0;
          });
        }
      }
    });
    super.initState();
  }

  Future<bool> getData() async {
    await Future<dynamic>.delayed(const Duration(milliseconds: 200));
    return true;
  }

  Future<List<Subject>> getSubjects() async {
    var res = await http.get(uri);

    if (res.statusCode == 200) {
      print(res.body);
      List<dynamic> body = jsonDecode(res.body);
      List<Subject> subjectList = body
          .map(
            (dynamic item) => Subject.fromJson(item),
      ).toList();

      return subjectList;
    } else {
      throw "Can't get subjects.";
    }
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  void addAllListData() {
    listViews.add(
      getListView(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.grey[50],
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: Stack(
          children: <Widget>[
            getListView(),
            getAppBarUI(),
            SizedBox(
              height: MediaQuery.of(context).padding.bottom,
            )
          ],
        ),
      ),
    );
  }

  Widget getListView(){
    return Container(
      decoration: new BoxDecoration(
        image: DecorationImage(
          image: new ExactAssetImage('assets/images/main_background.png'),
          fit: BoxFit.cover,
        ),
      ),
      child: FutureBuilder(
        future: subjectsList,
        builder: (BuildContext context, AsyncSnapshot<List<Subject>> snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return Center(child: Lottie.asset('assets/animations/dotloading.json'));
            case ConnectionState.done:
              if (snapshot.hasError) {
                return new Text('Error: ${snapshot.error}');
              }else {
                List<Subject> subjects = snapshot.data;
                return ListView.builder(
                  controller: scrollController,
                  itemCount: subjects.length,
                  padding: const EdgeInsets.only(top: 110, bottom: 25),
                  scrollDirection: Axis.vertical,
                  itemBuilder: (BuildContext context, int index) {
                    final int count = subjects.length > 10 ? 10 : subjects.length;
                    final Animation<double> animation =
                    Tween<double>(begin: 0.0, end: 1.0).animate(
                        CurvedAnimation(
                            parent: animationController,
                            curve: Interval(
                                (1 / count) * index, 1.0,
                                curve: Curves.fastOutSlowIn)));
                    animationController.forward();
                    return SubjectListView(
                      callback: () {},
                      subjectData: subjects[index],
                      animation: animation,
                      animationController: animationController,
                    );
                  },
                );
              }
              break;
            default:
              return Container();// also check your listWidget(snapshot) as it may return null.
          }
        },

      ),
    );
  }

  Widget getAppBarUI() {
    return Column(
      children: <Widget>[
        AnimatedBuilder(
          animation: animationController,
          builder: (BuildContext context, Widget child) {
            return FadeTransition(
              opacity: topBarAnimation,
              child: Transform(
                transform: Matrix4.translationValues(
                    0.0, 30 * (1.0 - topBarAnimation.value), 0.0),
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(topBarOpacity),
                    borderRadius: const BorderRadius.only(
                      bottomLeft: Radius.circular(32.0),
                    ),
                    boxShadow: <BoxShadow>[
                      BoxShadow(
                          color: Colors.grey
                              .withOpacity(0.4 * topBarOpacity),
                          offset: const Offset(1.1, 1.1),
                          blurRadius: 10.0),
                    ],
                  ),
                  child: Column(
                    children: <Widget>[
                      SizedBox(
                        height: MediaQuery.of(context).padding.top,
                      ),
                      Padding(
                        padding: EdgeInsets.only(
                            left: 16,
                            right: 16,
                            top: 2,
                            bottom: 8 - 8.0 * topBarOpacity),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Expanded(
                              child: Padding(
                                padding: const EdgeInsets.only(left: 50, top: 15, bottom: 20),
                                child: Text(
                                  'Choose a subject!',
                                  textAlign: TextAlign.left,
                                  style: TextStyle(
                                    fontFamily: "Roboto",
                                    fontWeight: FontWeight.w600,
                                    fontSize: 26 + 6 - 6 * topBarOpacity,
                                    letterSpacing: 1,
                                    color: Colors.black,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      )
                    ],
                  ),
                ),
              ),
            );
          },
        ),
      ],
    );
  }
}

onTap - элемент просмотра списка

child: GestureDetector(
            onTap: (){
              Navigator.push(context, MaterialPageRoute(builder: (context) {
                return PaperSelectScreen(
                  subjectName: subjectData.subject,
                  imageName: subjectData.image,
                );
              }));
            },

Третий экран - который включает в себя второй динамик c просмотр списка

class PaperSelectScreen extends StatefulWidget {

  @override
  _PaperSelectScreenState createState() => _PaperSelectScreenState();

  const PaperSelectScreen({Key key, this.subjectName, this.imageName}) : super(key: key);
  final subjectName;
  final imageName;
}

class _PaperSelectScreenState extends State<PaperSelectScreen> with TickerProviderStateMixin {

  static String subjectName;
  static String imageName;
  final ScrollController scrollController = ScrollController();
  AnimationController animationController;
  Animation<double> topBarAnimation;
  double topBarOpacity = 0;
  Future<List<Paper>> paperList;
  List<Widget> listViews = <Widget>[];
  String uri;

  @override
  void initState() {
    super.initState();
    subjectName = widget.subjectName;
    imageName = widget.imageName;
    uri = "xxxxxx";
    paperList = getPapers();
    animationController = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);

    topBarAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
        CurvedAnimation(
            parent: animationController,
            curve: Interval(0, 0.5, curve: Curves.fastOutSlowIn)));

    addAllListData();

    scrollController.addListener(() {
      if (scrollController.offset >= 24) {
        if (topBarOpacity != 1.0) {
          setState(() {
            topBarOpacity = 1.0;
          });
        }
      } else if (scrollController.offset <= 24 &&
          scrollController.offset >= 0) {
        if (topBarOpacity != scrollController.offset / 24) {
          setState(() {
            topBarOpacity = scrollController.offset / 24;
          });
        }
      } else if (scrollController.offset <= 0) {
        if (topBarOpacity != 0.0) {
          setState(() {
            topBarOpacity = 0.0;
          });
        }
      }
    });
  }

  Future<bool> getData() async {
    await Future<dynamic>.delayed(const Duration(milliseconds: 200));
    return true;
  }

  Future<List<Paper>> getPapers() async {
    var res = await http.get(uri);

    if (res.statusCode == 200) {
      print(res.body);
      List<dynamic> body = jsonDecode(res.body);
      List<Paper> paperList = body
          .map(
            (dynamic item) => Paper.fromJson(item),
      ).toList();
      return paperList;
    } else {
      throw "Can't get subjects.";
    }
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  void addAllListData() {
    listViews.add(
      getListView(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.grey[50],
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: Stack(
          children: <Widget>[
            getListView(),
            getAppBarUI(),
            /*Padding(
              padding: const EdgeInsets.only(left: 8,top: 30),
              child: IconButton(
                icon: Icon(Icons.arrow_back),
                color: Colors.black,
                onPressed: (){
                  Navigator.pop(context);
                },
              ),
            ),*/
            SizedBox(
              height: MediaQuery.of(context).padding.bottom,
            )
          ],
        ),
      ),
    );
  }

  Widget getListView(){
    return Container(
      decoration: new BoxDecoration(
        image: DecorationImage(
          image: new ExactAssetImage('assets/images/main_background.png'),
          fit: BoxFit.cover,
        ),
      ),
      child: FutureBuilder(
        future: paperList,
        builder: (BuildContext context, AsyncSnapshot<List<Paper>> snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return Center(child: Lottie.asset('assets/animations/dotloading.json'));
            case ConnectionState.done:
              if (snapshot.hasError) {
                return new Text('Error: ${snapshot.error}');
              }else {
                List<Paper> paper = snapshot.data;
                return ListView.builder(
                  controller: scrollController,
                  itemCount: paper.length,
                  padding: const EdgeInsets.only(top: 110, bottom: 25),
                  scrollDirection: Axis.vertical,
                  itemBuilder: (BuildContext context, int index) {
                    final int count =
                    paper.length > 10 ? 10 : paper.length;
                    final Animation<double> animation =
                    Tween<double>(begin: 0.0, end: 1.0).animate(
                        CurvedAnimation(
                            parent: animationController,
                            curve: Interval(
                                (1 / count) * index, 1.0,
                                curve: Curves.fastOutSlowIn)));
                    animationController.forward();
                    return PaperListView(
                      callback: () {},
                      paperData: paper[index],
                      image: imageName,
                      animation: animation,
                      animationController: animationController,
                    );
                  },
                );
              }
              break;
            default:
              return Container();// also check your listWidget(snapshot) as it may return null.
          }
        },

      ),
    );
  }

  Widget getAppBarUI() {
    return Column(
      children: <Widget>[
        AnimatedBuilder(
          animation: animationController,
          builder: (BuildContext context, Widget child) {
            return FadeTransition(
              opacity: topBarAnimation,
              child: Transform(
                transform: Matrix4.translationValues(
                    0.0, 30 * (1.0 - topBarAnimation.value), 0.0),
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(topBarOpacity),
                    borderRadius: const BorderRadius.only(
                      bottomLeft: Radius.circular(32.0),
                    ),
                    boxShadow: <BoxShadow>[
                      BoxShadow(
                          color: Colors.grey
                              .withOpacity(0.4 * topBarOpacity),
                          offset: const Offset(1.1, 1.1),
                          blurRadius: 10.0),
                    ],
                  ),
                  child: Column(
                    children: <Widget>[
                      SizedBox(
                        height: MediaQuery.of(context).padding.top,
                      ),
                      Padding(
                        padding: EdgeInsets.only(
                            left: 16,
                            right: 16,
                            top: 2,
                            bottom: 8 - 8.0 * topBarOpacity),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Expanded(
                              child: Padding(
                                padding: const EdgeInsets.only(left: 50, top: 15, bottom: 20),
                                child: Text(
                                  'Choose a paper!',
                                  textAlign: TextAlign.left,
                                  style: TextStyle(
                                    fontFamily: "Roboto",
                                    fontWeight: FontWeight.w600,
                                    fontSize: 26 + 6 - 6 * topBarOpacity,
                                    letterSpacing: 1,
                                    color: Colors.black,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      )
                    ],
                  ),
                ),
              ),
            );
          },
        ),
      ],
    );
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...