如何在抽屉内添加一个抽屉?
how to add one more drawer inside a drawer in flutter?
strong text 当我按下抽屉中的设置然后打开一个新抽屉时。当我点击抽屉中的按钮时如何实现抽屉
image1
image2
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(),
drawer: MyDrawer(),
body: Center(
child: Center(child: Text('Text')),
),
),
);
}
}
class MyDrawer extends StatefulWidget {
@override
_DrawerState createState() => _DrawerState();
}
class _DrawerState extends State<MyDrawer> {
int myIndex;
PageController _controller;
@override
void initState() {
super.initState();
_controller = PageController(initialPage: 0);
}
//The Logic where you change the pages
_onChangePage(int index){
if(index != 0) setState(() => myIndex = index); //change myIndex if you're Selecting between Settings and Explore
_controller.animateToPage(index.clamp(0, 1),
duration: const Duration(milliseconds: 500), curve: Curves.linear);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: PageView.builder(
controller: _controller,
physics: NeverScrollableScrollPhysics(), //so the user can not move between pages
itemCount: 2,
itemBuilder: (context, index) {
// Original Drawer
if (index == 0) return MyWidget(
explore: () => _onChangePage(1),
settings: () => _onChangePage(2),
);
//Second Drawer form the PageView
switch(myIndex){
case 1:
return MyExploreAll(goBack: () => _onChangePage(0));
case 2:
default:
return MySettings(goBack: () => _onChangePage(0));
}
},
)
);
}
}
//The Menu Drawer (Your first image)
class MyWidget extends StatelessWidget {
final VoidCallback explore;
final VoidCallback settings;
MyWidget({this.explore, this.settings});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
title: Text('Send Money'),
onTap: () => print('Send Money'),
),
ListTile(
title: Text('Explore All Amazon Pay'),
onTap: () => print('Explore All Amazon Pay'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Try Prime'),
onTap: () => print('Try Prime'),
),
ListTile(
title: Text('Explore All Programs'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: explore,
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Fun Zone'),
onTap: () => print('Fun Zone'),
),
const Divider(color: Colors.grey, thickness: 1,),
//More Stuff
ListTile(
title: Text('Settings'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: settings,
),
])
)
],
);
}
}
// The settings Drawer(second image)
class MySettings extends StatelessWidget {
final VoidCallback goBack;
MySettings({this.goBack});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
leading: const Icon(Icons.arrow_back_ios),
title: Text('Main Menu'),
onTap: goBack,
),
ListTile(
title: Text('Settings', textScaleFactor: 3,),
onTap: () => print('Settings'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Change Country'),
onTap: () => print('Change Country'),
),
ListTile(
title: Text('ETC'),
onTap: () => print('ETC'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Dummy Text'),
onTap: () => print('Dummy Text'),
),
])
)
],
);
}
}
class MyExploreAll extends StatelessWidget {
final VoidCallback goBack;
MyExploreAll({this.goBack});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
leading: const Icon(Icons.arrow_back_ios),
title: Text('Main Menu'),
onTap: goBack,
),
ListTile(
title: Text('Explore All', textScaleFactor: 3,),
onTap: () => print('Explore'),
),
const Divider(color: Colors.grey, thickness: 1,),
])
)
],
);
}
}
class MyInnerDrawer extends StatelessWidget {
final String name;
final PageController _controller;
MyInnerDrawer(this._controller, this.name);
@override
Widget build(BuildContext context) {
return Column(children: [
ListTile(
title: Text(name),
trailing: const Icon(Icons.arrow_back_ios),
onTap: () => _controller.animateToPage(0,
duration: const Duration(milliseconds: 500), curve: Curves.linear),
)
]);
}
}
使用 PageView.builder(),其中索引 0 是 firstPage(您的第一张带有常用抽屉的图像),索引 1 将是 selected 小部件(设置或探索)。我在 PageView 的索引 1 中的多个选项之间使用内部索引 myIndex select,那是因为如果我使用常规的 PageView 并给它一个所有选项的列表 [Drawer, Explorer, Settings] 如果你使用 controller.animateToPage() 你可以看到所有页面的过渡,例如,如果你在第 0 页并动画到第 2 页,你可以暂时看到第 1 页(就像你滚动一样水平)。
如果您不想看动画而直接跳转到该页面,您可以使用 controller.jumpToPage(index) 并且您不需要整个逻辑,它可能更容易
class _DrawerState extends State<MyDrawer> {
PageController _controller;
@override
void initState() {
super.initState();
_controller = PageController(initialPage: 0);
}
_onChangePage(int index){
_controller.jumpToPage(index);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: PageView.builder(
controller: _controller,
physics: NeverScrollableScrollPhysics(),
itemCount: 3,
itemBuilder: (context, index) {
switch(index){
case 1:
return MyExploreAll(goBack: () => _onChangePage(0));
case 2:
return MySettings(goBack: () => _onChangePage(0));
case 0:
default:
return MyWidget(
explore: () => _onChangePage(1),
settings: () => _onChangePage(2),
);
}
},
)
);
}
}
在这里,您只需告诉 PageView childCount 为 3(抽屉菜单、资源管理器和设置),然后执行一个 switch case 以在这 3 个索引之间跳转。您可以尝试在此示例中使用 animationToPage() 并查看我认为您的项目不希望出现的效果
这可能会晚一些,但另一个解决方案是在 Drawer
中构建 Scaffold
和 AppBar
,并利用 build-in 导航行为。
请注意以下示例使用 Builder
以编程方式打开 Drawer
,您也可以使用 GlobalKey
.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MultiDrawers(),
);
}
}
class MultiDrawers extends StatelessWidget {
const MultiDrawers({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Colors.teal),
drawer: const FirstDrawer(),
body: const Center(child: Text('multi-layer drawer example')),
);
}
}
class FirstDrawer extends StatelessWidget {
const FirstDrawer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Drawer(
child: Scaffold(
appBar: AppBar(
title: const Text('1st drawer'),
automaticallyImplyLeading: false, // hide hamburger icon
),
drawer: const SecondDrawer(),
body: Center(
child: Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
child: const Text('open 2nd drawer'),
);
}),
),
),
);
}
}
class SecondDrawer extends StatelessWidget {
const SecondDrawer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('2nd drawer'),
backgroundColor: Colors.pink,
),
body: const Center(
child: Text('this is 2nd drawer'),
),
);
}
}
strong text 当我按下抽屉中的设置然后打开一个新抽屉时。当我点击抽屉中的按钮时如何实现抽屉
image1 | image2 |
---|---|
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(),
drawer: MyDrawer(),
body: Center(
child: Center(child: Text('Text')),
),
),
);
}
}
class MyDrawer extends StatefulWidget {
@override
_DrawerState createState() => _DrawerState();
}
class _DrawerState extends State<MyDrawer> {
int myIndex;
PageController _controller;
@override
void initState() {
super.initState();
_controller = PageController(initialPage: 0);
}
//The Logic where you change the pages
_onChangePage(int index){
if(index != 0) setState(() => myIndex = index); //change myIndex if you're Selecting between Settings and Explore
_controller.animateToPage(index.clamp(0, 1),
duration: const Duration(milliseconds: 500), curve: Curves.linear);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: PageView.builder(
controller: _controller,
physics: NeverScrollableScrollPhysics(), //so the user can not move between pages
itemCount: 2,
itemBuilder: (context, index) {
// Original Drawer
if (index == 0) return MyWidget(
explore: () => _onChangePage(1),
settings: () => _onChangePage(2),
);
//Second Drawer form the PageView
switch(myIndex){
case 1:
return MyExploreAll(goBack: () => _onChangePage(0));
case 2:
default:
return MySettings(goBack: () => _onChangePage(0));
}
},
)
);
}
}
//The Menu Drawer (Your first image)
class MyWidget extends StatelessWidget {
final VoidCallback explore;
final VoidCallback settings;
MyWidget({this.explore, this.settings});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
title: Text('Send Money'),
onTap: () => print('Send Money'),
),
ListTile(
title: Text('Explore All Amazon Pay'),
onTap: () => print('Explore All Amazon Pay'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Try Prime'),
onTap: () => print('Try Prime'),
),
ListTile(
title: Text('Explore All Programs'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: explore,
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Fun Zone'),
onTap: () => print('Fun Zone'),
),
const Divider(color: Colors.grey, thickness: 1,),
//More Stuff
ListTile(
title: Text('Settings'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: settings,
),
])
)
],
);
}
}
// The settings Drawer(second image)
class MySettings extends StatelessWidget {
final VoidCallback goBack;
MySettings({this.goBack});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
leading: const Icon(Icons.arrow_back_ios),
title: Text('Main Menu'),
onTap: goBack,
),
ListTile(
title: Text('Settings', textScaleFactor: 3,),
onTap: () => print('Settings'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Change Country'),
onTap: () => print('Change Country'),
),
ListTile(
title: Text('ETC'),
onTap: () => print('ETC'),
),
const Divider(color: Colors.grey, thickness: 1,),
ListTile(
title: Text('Dummy Text'),
onTap: () => print('Dummy Text'),
),
])
)
],
);
}
}
class MyExploreAll extends StatelessWidget {
final VoidCallback goBack;
MyExploreAll({this.goBack});
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
ListTile(
leading: const Icon(Icons.arrow_back_ios),
title: Text('Main Menu'),
onTap: goBack,
),
ListTile(
title: Text('Explore All', textScaleFactor: 3,),
onTap: () => print('Explore'),
),
const Divider(color: Colors.grey, thickness: 1,),
])
)
],
);
}
}
class MyInnerDrawer extends StatelessWidget {
final String name;
final PageController _controller;
MyInnerDrawer(this._controller, this.name);
@override
Widget build(BuildContext context) {
return Column(children: [
ListTile(
title: Text(name),
trailing: const Icon(Icons.arrow_back_ios),
onTap: () => _controller.animateToPage(0,
duration: const Duration(milliseconds: 500), curve: Curves.linear),
)
]);
}
}
使用 PageView.builder(),其中索引 0 是 firstPage(您的第一张带有常用抽屉的图像),索引 1 将是 selected 小部件(设置或探索)。我在 PageView 的索引 1 中的多个选项之间使用内部索引 myIndex select,那是因为如果我使用常规的 PageView 并给它一个所有选项的列表 [Drawer, Explorer, Settings] 如果你使用 controller.animateToPage() 你可以看到所有页面的过渡,例如,如果你在第 0 页并动画到第 2 页,你可以暂时看到第 1 页(就像你滚动一样水平)。
如果您不想看动画而直接跳转到该页面,您可以使用 controller.jumpToPage(index) 并且您不需要整个逻辑,它可能更容易
class _DrawerState extends State<MyDrawer> {
PageController _controller;
@override
void initState() {
super.initState();
_controller = PageController(initialPage: 0);
}
_onChangePage(int index){
_controller.jumpToPage(index);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: PageView.builder(
controller: _controller,
physics: NeverScrollableScrollPhysics(),
itemCount: 3,
itemBuilder: (context, index) {
switch(index){
case 1:
return MyExploreAll(goBack: () => _onChangePage(0));
case 2:
return MySettings(goBack: () => _onChangePage(0));
case 0:
default:
return MyWidget(
explore: () => _onChangePage(1),
settings: () => _onChangePage(2),
);
}
},
)
);
}
}
在这里,您只需告诉 PageView childCount 为 3(抽屉菜单、资源管理器和设置),然后执行一个 switch case 以在这 3 个索引之间跳转。您可以尝试在此示例中使用 animationToPage() 并查看我认为您的项目不希望出现的效果
这可能会晚一些,但另一个解决方案是在 Drawer
中构建 Scaffold
和 AppBar
,并利用 build-in 导航行为。
请注意以下示例使用 Builder
以编程方式打开 Drawer
,您也可以使用 GlobalKey
.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MultiDrawers(),
);
}
}
class MultiDrawers extends StatelessWidget {
const MultiDrawers({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Colors.teal),
drawer: const FirstDrawer(),
body: const Center(child: Text('multi-layer drawer example')),
);
}
}
class FirstDrawer extends StatelessWidget {
const FirstDrawer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Drawer(
child: Scaffold(
appBar: AppBar(
title: const Text('1st drawer'),
automaticallyImplyLeading: false, // hide hamburger icon
),
drawer: const SecondDrawer(),
body: Center(
child: Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
child: const Text('open 2nd drawer'),
);
}),
),
),
);
}
}
class SecondDrawer extends StatelessWidget {
const SecondDrawer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('2nd drawer'),
backgroundColor: Colors.pink,
),
body: const Center(
child: Text('this is 2nd drawer'),
),
);
}
}