Я хочу добавить кнопку в «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.
),
),
),
],
);
}
}
Может быть, вы сможете попробовать PageView
виджет.
Просто оберните PageView в расширенный виджет и оберните его панелью приложений и нижней панелью вкладок. Чтобы изменить страницу, используйте контроллер просмотра страницы, анимация будет анимирована (конечно, ее можно отключить).
https://api.flutter.dev/flutter/widgets/PageView-class.html
Вы можете просто передать NeverScrollablePhysics() для PageView, тогда он не будет прокручиваться. И при щелчке нижней панели навигации при переходе на другую вкладку с помощью pageViewController.animateTo() установите для ее продолжительности значение Duration.Zero.
Именно то, что сказал @Ultranmus: вы можете изменить физику PageView на NeverScrollablePyshics, чтобы отключить прокрутку. Не стесняйтесь менять цвет вкладки, когда пользователь меняет вкладку после вызова animateTo() :)
Спасибо, @iStornZ и @Ultranmus. Я добавил PageView
в app.dart на основе ваших комментариев. Или правильно добавить его в «home.dart»? Но все же, когда я нажимаю кнопку в «home.dart», AppBar и BottomBar исчезают в месте назначения. Я добавил текущий код в тело вопроса, так что можете ли вы сказать мне, где я ошибаюсь?
Проверьте приведенный ниже код. В отредактированном коде вы неправильно обрабатывали виджет 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)
?
Можете ли вы добавить код главного экрана и экрана камеры? Я проверил свой код с помощью заполнителя. Я думаю, проблема находится в этих виджетах.
«home.dart» есть в тексте». cam.dart» также был добавлен.
я отредактировал ответ, проверьте его еще раз. Навигатор используется только тогда, когда вы хотите изменить контекст всего экрана. Но мы хотим изменить только страницы просмотра страниц, а не Navigator.push() использует pageViewController.jumpTo(). Просто передает ссылку контроллера на страницы просмотра страниц.
Извините за задержку с ответом. Я думал передать PageController
на HomeScreen()
. И это сработало. Но состояние выбора BottomNavigationBar не обновляется. Страница открыта, но значок «Домой» светится (возможно, ошибка в _buildIcon
). Если у вас есть решение этой проблемы, пожалуйста, дайте мне знать. Я поместил текущий код в раздел вопросов.
Причина, по которой значок не меняется, заключается в том, что вы не обновляете текущий индекс в родительском элементе и не вызываете setState для родительского элемента, который содержит нижнюю панель навигации. Давайте сделаем это, определив обратный вызов в родительском элементе, который обновляет индекс и вызывает setState и передает его на главный экран. И когда вы используете контроллер страниц, просто используйте этот обратный вызов
Я мог бы определить обратный вызов для «_BasePage» и передать его в качестве аргумента HomeScreen(). ありがとう (что означает «спасибо» по-японски) @Ultranmus.
Спасибо, iStornZ, попробую. Я просто хочу использовать кнопку home.dart или BottomNavigationBar для навигации, а не прокрутки. А также изменить цвет иконок при перемещении по страницам. (См. прикрепленное изображение.)