我正在尝试创建一个包,在其中向 BottomNavigationBar
添加一些功能。我想要一个通用的助手,在使用时,用另一个小部件包装底部导航小部件并更改其 onTap
方法。不幸的是,onTap
是最终的,无法更改。这迫使我在包代码中创建 BottomNavigationBar
小部件。这导致我必须将 BottomNavigationBar
的所有属性委托给用户。
理想情况下,我希望用户向我传递一个导航栏实例,并且只要传入的小部件具有可设置的 currentIndex
和 onTap
属性,我就会向其添加功能。
你会如何解决这个问题?
我想要实现的代码片段:
class ExtendedBottomNav extends StatefulWidget {
const ExtendedBottomNav({required this.bottomNavBar});
final BottomNavigationBar bottomNavBar;
@override
State<StatefulWidget> createState() => ExtendedBottomNavState();
}
class ExtendedBottomNavState extends State<ExtendedBottomNav> {
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
widget.bottomNavBar.currentIndex = _currentTabIndex;
widget.bottomNavBar.onTap = (int index) => {
// Some code, using _currentTabIndex
};
return Scaffold(
body: Text("Text"), // Some body
bottomNavigationBar: widget.bottomNavBar,
);
}
}
这是不可能的,因为'onTap' can't be used as a setter because it's final.
答案 0 :(得分:0)
我认为您可以通过扩展 BottomNavigationBar 小部件并覆盖来实现 onTap 函数并告诉用户传递 BottomNavigationBar 的新子类</p>
class NewBottomNavigationBar extends BottomNavigationBar {
NewBottomNavigationBar(List<BottomNavigationBarItem> items)
: super(items: []);
@override
ValueChanged<int>? onTap;
}
答案 1 :(得分:0)
您可以使用这种方法(使用空安全)。构造函数的参数我没有用过,大家可以根据自己的需要修改。
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
));
}
}
class CustomBottomNavigationBar extends StatelessWidget {
final BottomNavigationBar bar;
CustomBottomNavigationBar({ required this.bar});
BottomNavigationBar? customBar;
@override
Widget build(BuildContext context) {
customBar = BottomNavigationBar(
items: bar.items,
currentIndex: bar.currentIndex,
selectedItemColor: bar.selectedItemColor,
onTap: (int index){
// here you can add your additional code
print("hi");
if(bar.onTap != null)
bar.onTap!(index);
},
);
return Container(
child:customBar);
}
}
没有空安全
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
));
}
}
class CustomBottomNavigationBar extends StatelessWidget {
final BottomNavigationBar bar;
CustomBottomNavigationBar({ @required this.bar});
BottomNavigationBar customBar;
@override
Widget build(BuildContext context) {
customBar = BottomNavigationBar(
items: bar.items,
currentIndex: bar.currentIndex,
selectedItemColor: bar.selectedItemColor,
onTap: (int index){
print("hi");
if(bar.onTap != null)
bar.onTap(index);
},
);
return Container(
child:customBar);
}
}