我有我的网站在Flutter,我需要为我的导航栏创建一个插件,当你点击NavbarItem的用户名是(users.firstName)。下面我与你分享的代码。
class NavBar extends StatelessWidget {
const NavBar({Key? key});
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final user = Provider.of<AuthProvider>(context).user!;
final token = LocalStorage.prefs.getString('token');
return Container(
width: double.infinity,
height: 75,
decoration: buildBoxDecoration(),
child: Row(
children: [
if (size.width <= 779) ...[
IconButton(
onPressed: () {
SideMenuProvider.openMenu();
},
icon: const Icon(Icons.menu_outlined),
),
const Spacer(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 2),
child: Container(
width: 250,
child: const AutoSizeText(
'SISTEMA WEB DE COSTOS Y RENTABILIDAD DEL PROCESO DEL CULTIVO DEL BANANO',
style: TextStyle(
fontWeight: FontWeight.bold,
),
maxLines: 5, // Número máximo de líneas permitidas
minFontSize: 10, // Tamaño de fuente mínimo
maxFontSize: 30, // Tamaño de fuente máximo
overflow: TextOverflow.ellipsis, // Opción de desbordamiento
),
),
),
],
if (size.width >= 779) ...[
const SizedBox(
width: 5,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 2),
child: Container(
width: 250,
child: const AutoSizeText(
'SISTEMA WEB DE COSTOS Y RENTABILIDAD DEL PROCESO DEL CULTIVO DEL BANANO',
style: TextStyle(
fontWeight: FontWeight.bold,
),
maxLines: 5, // Número máximo de líneas permitidas
minFontSize: 10, // Tamaño de fuente mínimo
maxFontSize: 30, // Tamaño de fuente máximo
overflow: TextOverflow.ellipsis, // Opción de desbordamiento
),
),
),
const Spacer(),
NavbarItem(
text: 'Inicio',
icon: Icons.home_sharp,
onPressed: () {
NavigationService.replaceTo(Flurorouter.dashboardRoute);
}),
/*NavbarItem(
text: 'Opciones de perfil',
icon: Icons.settings,
onPressed: () {}),*/
NavbarItem(
text: 'Datos',
icon: Icons.people,
onPressed: () {
NavigationService.replaceTo('/dashboard/info/$token');
},
isActive: false),
NavbarItem(
text: 'Password',
icon: Icons.people,
onPressed: () {
NavigationService.replaceTo(Flurorouter.changePassRoute);
},
isActive: false),
NavbarItem(
text: user.firstName,
icon: Icons.people,
onPressed: () {
//crearMenu(context);
},
isActive: false),
NavbarItem(
text: 'Salir',
icon: Icons.exit_to_app_outlined,
onPressed: () {
Provider.of<AuthProvider>(context, listen: false).logout();
},
),
],
],
),
);
}
BoxDecoration buildBoxDecoration() => const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft, // Comienza desde la izquierda
end: Alignment.centerRight, // Termina en la derecha
colors: [
Color(0xFF679C64), // Color de inicio
Color(0xFFADCFAB), // Color de finalización
],
),
boxShadow: [
BoxShadow(
blurRadius: 5,
color: Colors.black12,
)
]);
字符串
NavbarItem包括:
class NavbarItem extends StatefulWidget {
final String text;
final IconData icon;
final bool isActive;
final Function onPressed;
const NavbarItem({
required this.text,
required this.icon,
this.isActive = false,
required this.onPressed,
});
@override
State<NavbarItem> createState() => _NavbarItemState();
}
class _NavbarItemState extends State<NavbarItem> {
bool isHover = false;
@override
Widget build(BuildContext context) {
return Container(
child: InkWell(
onTap: widget.isActive ? null : () => widget.onPressed(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: MouseRegion(
onEnter: (_) => setState(() {
isHover = true;
}),
onExit: (_) => setState(() {
isHover = false;
}),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Icon(widget.icon),
Text(
widget.text,
style: TextStyle(
decoration: isHover
? TextDecoration.underline
: TextDecoration.none,
),
)
],
),
),
),
),
);
}
}
型
我该怎么做?
我需要改变一些小部件的NavbarItem,使我能够实现显示更多的选项来获得一个插件的行为。我还想知道这些插件选项是否可以自定义,就像下面的小部件一样,这是一个AnimatedContainer,我使用的侧菜单,我喜欢它的工作方式,我想集成该小部件作为自定义选项:
class SidebarItem extends StatefulWidget {
final String text;
final Function onPressed;
final bool isActive;
final IconData icon;
const SidebarItem({
Key? key,
required this.text,
required this.onPressed,
this.isActive = false,
required this.icon,
}) : super(key: key);
@override
State<SidebarItem> createState() => _SidebarItemState();
}
class _SidebarItemState extends State<SidebarItem> {
bool isHover = false;
@override
Widget build(BuildContext context) {
Color backgroundColor = isHover
? const Color(0xFF184D26)
: widget.isActive
? const Color(0xFF184D26)
: Colors.transparent;
return AnimatedContainer(
duration: const Duration(milliseconds: 250),
color: backgroundColor,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.isActive ? null : () => widget.onPressed(),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 30, vertical: 10),
child: MouseRegion(
onEnter: (_) => setState(() {
isHover = true;
}),
onExit: (_) => setState(() {
isHover = false;
}),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(widget.icon),
const SizedBox(
width: 5,
),
Text(
widget.text,
/*style: GoogleFonts.roboto(
fontSize: 14,
color: Colors.black.withOpacity(0.8),
),*/
),
],
),
),
)),
));
}
}
型
我想实现这样的东西:我需要显示两个选项'更改密码'和'更新信息'. enter image description here
MRE
这是我的主要:
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'BananoProject',
initialRoute: '/',
onGenerateRoute: Flurorouter.router.generator,
navigatorKey: NavigationService.navigatorKey,
scaffoldMessengerKey: NotificationsService.messengerKey,
builder: (_, child) {
final authProvider = Provider.of<AuthProvider>(context);
if (authProvider.authStatus == AuthStatus.checking){
return SplashLayout();
}
if(authProvider.authStatus == AuthStatus.authenticated){
return DashboardLayout(child: child!);
型
登录后,用户可以访问DashboardLayout,这是应用程序的主窗口。
class DashboardLayout extends StatefulWidget {
final Widget child;
const DashboardLayout({ required this.child});
@override
State<DashboardLayout> createState() => _DashboardLayoutState();
}
class _DashboardLayoutState extends State<DashboardLayout>
with SingleTickerProviderStateMixin {
@override
void initState() {
// TODO: implement initState
super.initState();
SideMenuProvider.menuController = AnimationController(
vsync: this, duration: const Duration(microseconds: 300));
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/moduls_background.jpeg'),
fit: BoxFit.cover,
),
),
child: Stack(
children: [
Row(
children: [
Expanded(
child: Column(
children: [
const NavBar( ),
//navbar
Expanded(child: widget.child),
],
),
),
],
),
],
),
));
}
}
型
正如你所看到的,导航栏在 Jmeter 板布局中,只有登录的用户可以看到它。当实现你的共享代码时,我得到了提到的错误,在这里我分享导航栏:
enum Options { changePassword, logout }
void onSelected(item) {
switch (item) {
case Options.changePassword:
debugPrint('Change Password pressed');
break;
case Options.logout:
debugPrint('Change Password pressed');
break;
}
}
class NavBar extends StatelessWidget {
const NavBar({Key? key});
@override
Widget build(BuildContext context) {
final navbarItem = AbsorbPointer(
child: NavbarItem(
text: 'Salir',
icon: Icons.exit_to_app_outlined,
onPressed: () {
print('Hola');
},
),
);
List<PopupMenuEntry<Options>> itemBuilder(context) => [
const PopupMenuItem(
value: Options.changePassword,
child: Text('Change Password'),
),
const PopupMenuItem(
value: Options.logout,
child: Text('Logout'),
),
];
final size = MediaQuery.of(context).size;
final user = Provider.of<AuthProvider>(context).user!;
final token = LocalStorage.prefs.getString('token');
return Builder(builder: (BuildContext context) {
return Container(
width: double.infinity,
height: 75,
decoration: buildBoxDecoration(),
child: Row(
children: [
if (size.width <= 779) ...[
IconButton(
onPressed: () {
SideMenuProvider.openMenu();
},
icon: const Icon(Icons.menu_outlined),
),
const Spacer(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 2),
child: Container(
width: 250,
child: const AutoSizeText(
'SISTEMA WEB DE COSTOS Y RENTABILIDAD DEL PROCESO DEL CULTIVO DEL BANANO',
style: TextStyle(
fontWeight: FontWeight.bold,
),
maxLines: 5, // Número máximo de líneas permitidas
minFontSize: 10, // Tamaño de fuente mínimo
maxFontSize: 30, // Tamaño de fuente máximo
overflow: TextOverflow.ellipsis, // Opción de desbordamiento
),
),
),
],
if (size.width >= 779) ...[
const SizedBox(
width: 5,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 2),
child: Container(
width: 250,
child: const AutoSizeText(
'SISTEMA WEB DE COSTOS Y RENTABILIDAD DEL PROCESO DEL CULTIVO DEL BANANO',
style: TextStyle(
fontWeight: FontWeight.bold,
),
maxLines: 5, // Número máximo de líneas permitidas
minFontSize: 10, // Tamaño de fuente mínimo
maxFontSize: 30, // Tamaño de fuente máximo
overflow: TextOverflow.ellipsis, // Opción de desbordamiento
),
),
),
const Spacer(),
NavbarItem(
text: 'Inicio',
icon: Icons.home_sharp,
onPressed: () {
NavigationService.replaceTo(Flurorouter.dashboardRoute);
}),
/*NavbarItem(
text: 'Opciones de perfil',
icon: Icons.settings,
onPressed: () {}),*/
NavbarItem(
text: 'Datos',
icon: Icons.people,
onPressed: () {
NavigationService.replaceTo('/dashboard/info/$token');
},
isActive: false),
NavbarItem(
text: 'Password',
icon: Icons.people,
onPressed: () {
NavigationService.replaceTo(Flurorouter.changePassRoute);
},
isActive: false),
NavbarItem(
text: user.firstName,
icon: Icons.people,
onPressed: () {
//crearMenu(context);
},
isActive: false),
Container(
width: 50,
child: Overlay(
initialEntries: [
OverlayEntry(builder: (context) {
return PopupMenuButton(
onSelected: onSelected,
itemBuilder: itemBuilder,
child: navbarItem,
);
})
],
)),
NavbarItem(
text: 'Salir',
icon: Icons.exit_to_app_outlined,
onPressed: () {
Provider.of<AuthProvider>(context, listen: false).logout();
},
),
],
],
),
);
});
}
BoxDecoration buildBoxDecoration() => const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft, // Comienza desde la izquierda
end: Alignment.centerRight, // Termina en la derecha
colors: [
Color(0xFF679C64), // Color de inicio
Color(0xFFADCFAB), // Color de finalización
],
),
boxShadow: [
BoxShadow(
blurRadius: 5,
color: Colors.black12,
)
]);
型
1条答案
按热度按时间iswrvxsc1#
试试
PopupMenuButton
最终外观可能因主题而异。
100d1x
的字符串
使用
child
参数指定要显示为按钮的内容,使用onSelected
参数指定要如何处理在PopupMenuItem
处提供的值,使用itemBuilder
参数来生成项。1.在这种情况下,请声明一个选项列表或枚举,以使其更具描述性。
字符串
1.用作按钮的子级,否则它可能显示默认的3点图标。这是
NavbarItem
,用AbsorbPointer
Package 以覆盖其onPressed
函数。型
1.已选择
型
1.项目生成器
型
1.在您想使用的地方进行调整
型
MRE
型