Как создать навигатор с тем же пунктом назначения, что и BottomNavigationBar?

Я хочу добавить кнопку в «src/screens/home.dart», которая имеет тот же переход, что и BottomNavigationBar в «src/app.dart». Конечно, сохраняя AppBar и BottomNavigationBar.

В моем коде, если я перейду от кнопки «Домой» к экрану камеры, он оставит app.dart. Также вполне вероятно, что пользовательский интерфейс следует пересмотреть.

После этого перехода я хочу, чтобы загорелся значок BottomNavigationBar. При переходе на экран без значков я хочу, чтобы все значки были затемнены. То же, что и процесс app.dart _buildIcon.

Я начал изучать Flutter вчера, поэтому, если вы обнаружите какой-нибудь странный код, дайте мне знать. Спасибо.

введите сюда описание изображения

Редактировать:.
Я поставил HomeScreen()PageController и смог взять на себя управление AppBar и BottomBar, но выбор BottomBar не обновляется.

основной.дарт:

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

import 'src/app.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,]);
  runApp(
    const MyApp()
  );
}

источник/app.dart:

import 'package:flutter/material.dart';

import 'screens/home.dart';
import 'screens/cam.dart';
import 'screens/setting.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent,
      ),
      home: BasePage(),
    );
  }
}

class BasePage extends StatefulWidget{
  @override
  _BasePage createState() => _BasePage();
}


class _BasePage extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {

    var TabItem = {
      'home':[0, Icons.home, Colors.green, HomeScreen(pageController: _pageController)],
      'cam':[1, Icons.video_camera_back, Colors.lightGreen, const CamScreen()],
      'setting':[2, Icons.settings, Colors.yellow, const SettingScreen()]
    };

    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: PageView(
        controller: _pageController,
        physics: const NeverScrollableScrollPhysics(),
        children: TabItem.values.map((value) => value[3] as Widget).toList(),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.entries.map(
            (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.value[1] as IconData, tabItem.value[2]as Color, selected: _currentIndex == tabItem.value[0]),
              label: tabItem.key,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,          
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3); 
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

источник/экраны/home.dart:

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  final PageController pageController;
  HomeScreen({super.key, required this.pageController,});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: (){pageController.jumpToPage(1);},
            child: Container(
              // Omit the code here.
            ),
          ),
        ),
      ],
    );
  }
}

src/экраны/cam.dart

import 'package:flutter/material.dart';

class CamScreen extends StatelessWidget {
  const CamScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:
          const Center(child: Text('camera', style: TextStyle(fontSize: 32.0))),
    );
  }
}

РЕШЕНО src/app.dart

import 'package:flutter/material.dart';

import 'screens/home.dart';
import 'screens/cam.dart';
import 'screens/setting.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent,
      ),
      home: BasePage(),
    );
  }
}

class BasePage extends StatefulWidget{
  @override
  _BasePage createState() => _BasePage();
}

class _BasePage extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  void changeIndex(index){
    setState(() {
      _currentIndex = index;
      _pageController.jumpToPage(index);
    });
  }
  
  @override
  Widget build(BuildContext context) {

    var TabItem = {
      'home':[0, Icons.home, Colors.green, HomeScreen(pageController: _pageController, changeIndex: changeIndex,)],
      'cam':[1, Icons.video_camera_back, Colors.lightGreen, const CamScreen()],
      'setting':[2, Icons.settings, Colors.yellow, const SettingScreen()]
    };

    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: PageView(
        controller: _pageController,
        physics: const NeverScrollableScrollPhysics(),
        children: TabItem.values.map((value) => value[3] as Widget).toList(),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.entries.map(
            (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.value[1] as IconData, tabItem.value[2]as Color, selected: _currentIndex == tabItem.value[0]),
              label: tabItem.key,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,          
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3); 
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

src/экраны/home.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  final PageController pageController;
  final void Function(int) changeIndex;
  const HomeScreen({super.key, required this.pageController, required this.changeIndex});


  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: (){changeIndex(1);},
            child: Container(
              // Omit the code here.
            ),
          ),
        ),
      ],
    );
  }
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
97
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Может быть, вы сможете попробовать PageView виджет.

Просто оберните PageView в расширенный виджет и оберните его панелью приложений и нижней панелью вкладок. Чтобы изменить страницу, используйте контроллер просмотра страницы, анимация будет анимирована (конечно, ее можно отключить).

https://api.flutter.dev/flutter/widgets/PageView-class.html

Спасибо, iStornZ, попробую. Я просто хочу использовать кнопку home.dart или BottomNavigationBar для навигации, а не прокрутки. А также изменить цвет иконок при перемещении по страницам. (См. прикрепленное изображение.)

beginner T 11.04.2024 10:51

Вы можете просто передать NeverScrollablePhysics() для PageView, тогда он не будет прокручиваться. И при щелчке нижней панели навигации при переходе на другую вкладку с помощью pageViewController.animateTo() установите для ее продолжительности значение Duration.Zero.

Ultranmus 11.04.2024 11:02

Именно то, что сказал @Ultranmus: вы можете изменить физику PageView на NeverScrollablePyshics, чтобы отключить прокрутку. Не стесняйтесь менять цвет вкладки, когда пользователь меняет вкладку после вызова animateTo() :)

iStornZ 11.04.2024 11:17

Спасибо, @iStornZ и @Ultranmus. Я добавил PageView в app.dart на основе ваших комментариев. Или правильно добавить его в «home.dart»? Но все же, когда я нажимаю кнопку в «home.dart», AppBar и BottomBar исчезают в месте назначения. Я добавил текущий код в тело вопроса, так что можете ли вы сказать мне, где я ошибаюсь?

beginner T 12.04.2024 05:05
Ответ принят как подходящий

Проверьте приведенный ниже код. В отредактированном коде вы неправильно обрабатывали виджет MyApp, вам необходимо передать домашний виджет в MaterialApp. И здесь вам не нужен onPageChange, потому что он используется, когда вы прокручиваете PageView и хотите внести некоторые изменения при смене страницы, но в вашем случае вы меняете его вручную на нижней панели навигации, щелкните

void main()  {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    // postData();
    // fetchIPAddress();
  }

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BasePage(),
    );
  }
}

enum TabItem {
  home(
      title: 'home',
      icon: Icons.home,
      color: Colors.green,
      page: HomeScreen()
  ),
  cam(
      title: 'cam',
      icon: Icons.video_camera_back,
      color: Colors.lightGreen,
      page: CamScreen()
  ),
  setting(
      title: 'setting',
      icon: Icons.settings,
      color: Colors.cyan,
      page: SettingScreen()
  );

  const TabItem({
    required this.title,
    required this.icon,
    required this.color,
    required this.page,
  });
  final String title;
  final IconData icon;
  final Color color;
  final Widget page;
}

class BasePage extends StatefulWidget {
  const BasePage({super.key});

  @override
  State<BasePage> createState() => _BasePageState();
}

class _BasePageState extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: Expanded(
        child: PageView(
          controller: _pageController,
          physics: const NeverScrollableScrollPhysics(),
          children: TabItem.values.map(
                  (tabItem) => tabItem.page
          ).toList(),
        ),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.values.map(
                (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.icon, tabItem.color, selected: _currentIndex==tabItem.index),
              label: tabItem.title,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3);
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

Редактировать: Проблема, когда вы нажимаете кнопку на HomeScreen и переходите на другую страницу, удаляете панель приложений и нижнюю панель навигации, связана с тем, что вы используете Navigator.push(). Что вы хотите сделать, так это перейти с одной страницы на другую при просмотре страницы, а затем использовать _pageController.jumpTo(). Просто передайте контроллер страницам, которые предполагают переход на другие страницы. Когда вы используете Навигатор, вы меняете весь экран, но это не то, чего мы хотим. Мы хотим только изменить страницы в представлении страницы, чтобы сделать это с помощью pageViewController.

Спасибо Ultranmus, что сообщили мне. Но с вашим кодом, когда я нажимаю кнопку, которую я поместил в «home.dart», и перехожу к «cam.dart», AppBar и BottomBar исчезают. Это не то, чего я хочу. Это просто идея, но могу ли я передать _pageController, указанный в PageView, в качестве параметра, например HomeScreen(_pageController)?

beginner T 12.04.2024 09:26

Можете ли вы добавить код главного экрана и экрана камеры? Я проверил свой код с помощью заполнителя. Я думаю, проблема находится в этих виджетах.

Ultranmus 12.04.2024 10:32

«home.dart» есть в тексте». cam.dart» также был добавлен.

beginner T 12.04.2024 10:50

я отредактировал ответ, проверьте его еще раз. Навигатор используется только тогда, когда вы хотите изменить контекст всего экрана. Но мы хотим изменить только страницы просмотра страниц, а не Navigator.push() использует pageViewController.jumpTo(). Просто передает ссылку контроллера на страницы просмотра страниц.

Ultranmus 12.04.2024 11:21

Извините за задержку с ответом. Я думал передать PageController на HomeScreen(). И это сработало. Но состояние выбора BottomNavigationBar не обновляется. Страница открыта, но значок «Домой» светится (возможно, ошибка в _buildIcon). Если у вас есть решение этой проблемы, пожалуйста, дайте мне знать. Я поместил текущий код в раздел вопросов.

beginner T 15.04.2024 03:46

Причина, по которой значок не меняется, заключается в том, что вы не обновляете текущий индекс в родительском элементе и не вызываете setState для родительского элемента, который содержит нижнюю панель навигации. Давайте сделаем это, определив обратный вызов в родительском элементе, который обновляет индекс и вызывает setState и передает его на главный экран. И когда вы используете контроллер страниц, просто используйте этот обратный вызов

Ultranmus 15.04.2024 06:27

Я мог бы определить обратный вызов для «_BasePage» и передать его в качестве аргумента HomeScreen(). ありがとう (что означает «спасибо» по-японски) @Ultranmus.

beginner T 15.04.2024 07:56

Другие вопросы по теме