Compare commits
7 Commits
flutter_bo
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89eebe3ad8 | ||
|
|
2a69cb706b | ||
|
|
74f9c288ab | ||
|
|
72c3cc607d | ||
|
|
1aeab4fa64 | ||
|
|
34d8e6dd75 | ||
|
|
25b3bc16b2 |
@@ -1,4 +1,2 @@
|
||||
01: 分析 push 方法。
|
||||
A、B、C 三个界面跳转。
|
||||
|
||||
02: replace
|
||||
@@ -23,7 +23,7 @@ class MyApp extends StatelessWidget {
|
||||
titleTextStyle: TextStyle(color: Colors.black,fontSize: 18,fontWeight: FontWeight.bold)
|
||||
)
|
||||
),
|
||||
home: const PageA(),
|
||||
home: const HomePage(),
|
||||
onUnknownRoute: _onUnknownRoute,
|
||||
);
|
||||
}
|
||||
@@ -46,3 +46,28 @@ class MyApp extends StatelessWidget {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Color bgColor = Color(0xffCCFFFF);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: bgColor,
|
||||
appBar: AppBar(title: const Text('主页'),
|
||||
backgroundColor: bgColor,
|
||||
),
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: ()=>toPageA(context),
|
||||
child: const Text('Push A'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void toPageA(BuildContext context){
|
||||
Navigator.of(context).pushNamed('/a');
|
||||
}
|
||||
}
|
||||
|
||||
4
lib/09/节点介绍.txt
Normal file
4
lib/09/节点介绍.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
01: 分析 pop 方法。
|
||||
A、B、C 三个界面跳转。
|
||||
|
||||
02: 分析 popUntil 方法。
|
||||
46
lib/10/app_info.dart
Normal file
46
lib/10/app_info.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppInfo extends StatelessWidget {
|
||||
const AppInfo({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const String msg = 'FlutterUnit 是一个辅助开发者,了解 Flutter 组件和编程技术的开源项目。 ';
|
||||
const String msg2 = '由张风捷特烈维护,开源地址:\n https://github.com/toly1994328/FlutterUnit ';
|
||||
|
||||
double height = MediaQuery.of(context).size.height;
|
||||
return SizedBox(
|
||||
height: height*(1-0.618),
|
||||
child: Column(
|
||||
children: [
|
||||
AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
automaticallyImplyLeading: false,
|
||||
centerTitle: true,
|
||||
leading: Align(child: FlutterLogo()),
|
||||
actions: [
|
||||
CloseButton()
|
||||
],
|
||||
title: Column(
|
||||
children: [
|
||||
Text('FlutterUnit',style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold)),
|
||||
Text('v2.9.3',style: TextStyle(fontSize: 12,),),
|
||||
],
|
||||
),),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0,vertical: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// direction: Axis.vertical,
|
||||
children: [
|
||||
Text(msg,style: TextStyle(color: Colors.grey),),
|
||||
const SizedBox(height: 8,),
|
||||
Text(msg2,style: TextStyle(color: Colors.grey),),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
107
lib/10/cupertino_context_menu_demo.dart
Normal file
107
lib/10/cupertino_context_menu_demo.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [CupertinoContextMenu].
|
||||
|
||||
final DecorationTween _tween = DecorationTween(
|
||||
begin: BoxDecoration(
|
||||
color: CupertinoColors.systemPurple,
|
||||
boxShadow: const <BoxShadow>[],
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
),
|
||||
end: BoxDecoration(
|
||||
color: CupertinoColors.systemPurple,
|
||||
boxShadow: CupertinoContextMenu.kEndBoxShadow,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
),
|
||||
);
|
||||
|
||||
class CupertinoContextMenuDemo extends StatelessWidget {
|
||||
const CupertinoContextMenuDemo({super.key});
|
||||
|
||||
// Or just do this inline in the builder below?
|
||||
static Animation<Decoration> _boxDecorationAnimation(
|
||||
Animation<double> animation) {
|
||||
return _tween.animate(
|
||||
CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Interval(
|
||||
0.0,
|
||||
CupertinoContextMenu.animationOpensAt,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: const CupertinoNavigationBar(
|
||||
middle: Text('CupertinoContextMenu 案例'),
|
||||
),
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 100,
|
||||
height: 100,
|
||||
child: CupertinoContextMenu.builder(
|
||||
actions: <Widget>[
|
||||
CupertinoContextMenuAction(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
isDefaultAction: true,
|
||||
trailingIcon: CupertinoIcons.doc_on_clipboard_fill,
|
||||
child: const Text('Copy'),
|
||||
),
|
||||
CupertinoContextMenuAction(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
trailingIcon: CupertinoIcons.share,
|
||||
child: const Text('Share'),
|
||||
),
|
||||
CupertinoContextMenuAction(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
trailingIcon: CupertinoIcons.heart,
|
||||
child: const Text('Favorite'),
|
||||
),
|
||||
CupertinoContextMenuAction(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
isDestructiveAction: true,
|
||||
trailingIcon: CupertinoIcons.delete,
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
builder: (BuildContext context, Animation<double> animation) {
|
||||
final Animation<Decoration> boxDecorationAnimation =
|
||||
_boxDecorationAnimation(animation);
|
||||
|
||||
return Container(
|
||||
decoration:
|
||||
animation.value < CupertinoContextMenu.animationOpensAt
|
||||
? boxDecorationAnimation.value
|
||||
: null,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: CupertinoColors.systemPurple,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
),
|
||||
child: const FlutterLogo(size: 250.0),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
83
lib/10/dropdown_button_color.dart
Normal file
83
lib/10/dropdown_button_color.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [DropdownButton.selectedItemBuilder].
|
||||
|
||||
const Map<String, Color> kColors = <String, Color>{
|
||||
'红色': Colors.red,
|
||||
'黄色': Colors.yellowAccent,
|
||||
'蓝色': Colors.blue,
|
||||
'绿色': Colors.greenAccent,
|
||||
'橙色': Colors.orange,
|
||||
'紫色': Colors.purple,
|
||||
};
|
||||
|
||||
class DropdownButtonColor extends StatefulWidget {
|
||||
const DropdownButtonColor({super.key});
|
||||
|
||||
@override
|
||||
State<DropdownButtonColor> createState() => _DropdownButtonColorState();
|
||||
}
|
||||
|
||||
class _DropdownButtonColorState extends State<DropdownButtonColor> {
|
||||
String selectedItem = kColors.keys.first;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text('选择颜色:', style: Theme.of(context).textTheme.bodyLarge),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: DropdownButton<String>(
|
||||
value: selectedItem,
|
||||
onChanged: (String? value) {
|
||||
setState(() => selectedItem = value!);
|
||||
},
|
||||
selectedItemBuilder: _buildSelectItem,
|
||||
items: _buildItems(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<DropdownMenuItem<String>> _buildItems(){
|
||||
return kColors.keys.map<DropdownMenuItem<String>>((String key) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: key,
|
||||
child: Wrap(
|
||||
spacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 14,
|
||||
height: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: kColors[key],
|
||||
borderRadius: BorderRadius.circular(2)),
|
||||
),
|
||||
Text(key),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<Widget> _buildSelectItem(BuildContext context) {
|
||||
return kColors.values.map<Widget>((Color color) {
|
||||
return Align(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(2)),
|
||||
constraints: const BoxConstraints(minWidth: 24,maxHeight: 24),
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
137
lib/10/main.dart
Normal file
137
lib/10/main.dart
Normal file
@@ -0,0 +1,137 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
|
||||
import 'app_info.dart';
|
||||
import 'cupertino_context_menu_demo.dart';
|
||||
import 'dropdown_button_color.dart';
|
||||
import 'more_pop_icon.dart';
|
||||
import 'search_anchor_demo.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
supportedLocales: const [
|
||||
Locale('zh', 'CN'),
|
||||
],
|
||||
locale: const Locale('zh', 'CN'),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const HomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("弹出层测试"),
|
||||
actions: [
|
||||
MorePopIcon(onTapItem: _onTapItem,)
|
||||
],
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: showConformDialog,
|
||||
child: Text('关于应用'),
|
||||
),
|
||||
DropdownButtonColor(),
|
||||
ElevatedButton(
|
||||
onPressed: _showModalBottomSheet,
|
||||
child: Text('showModalBottomSheet'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _showCupertinoModalPopup,
|
||||
child: Text('showCupertinoModalPopup'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _toSearchAnchor,
|
||||
child: Text('SearchAnchor 案例'),
|
||||
), ElevatedButton(
|
||||
onPressed: _toCupertinoContextMenu,
|
||||
child: Text('CupertinoContextMenu 案例'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showConformDialog(){
|
||||
showDialog(context: context, builder: _buildAbout);
|
||||
// showCupertinoModalPopup(context: context, builder: builder)
|
||||
// showCupertinoDialog(context: context, builder: _buildAbout);
|
||||
}
|
||||
|
||||
void _showModalBottomSheet(){
|
||||
showModalBottomSheet(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8)
|
||||
),
|
||||
context: context, builder: (_)=>AppInfo());
|
||||
}
|
||||
|
||||
void _showCupertinoModalPopup(){
|
||||
showCupertinoModalPopup(
|
||||
context: context, builder: (_)=>Material(child: const AppInfo()));
|
||||
}
|
||||
|
||||
Widget _buildAbout(BuildContext context){
|
||||
const String msg = 'FlutterUnit 是一个辅助开发者,了解 Flutter 组件和编程技术的开源项目。';
|
||||
return const AboutDialog(
|
||||
applicationName: "FlutterUnit",
|
||||
applicationVersion: "v2.9.3",
|
||||
applicationIcon: FlutterLogo(),
|
||||
children: [
|
||||
Text(msg,style: TextStyle(color: Colors.grey),)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onTapItem(MenuAction value) {
|
||||
print(value.label);
|
||||
switch(value){
|
||||
case MenuAction.setting:
|
||||
break;
|
||||
case MenuAction.about:
|
||||
showConformDialog();
|
||||
break;
|
||||
case MenuAction.help:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _toSearchAnchor() {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_)=>SearchAnchorDemo()));
|
||||
|
||||
}
|
||||
|
||||
void _toCupertinoContextMenu() {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_)=>CupertinoContextMenuDemo()));
|
||||
}
|
||||
}
|
||||
58
lib/10/more_pop_icon.dart
Normal file
58
lib/10/more_pop_icon.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum MenuAction implements Comparable<MenuAction> {
|
||||
setting(label: '应用设置', iconData: Icons.settings),
|
||||
about(label: '关于应用', iconData: Icons.info),
|
||||
help(label: '帮助中心', iconData: Icons.help);
|
||||
|
||||
final String label;
|
||||
final IconData iconData;
|
||||
|
||||
const MenuAction({
|
||||
required this.label,
|
||||
required this.iconData,
|
||||
});
|
||||
|
||||
@override
|
||||
int compareTo(MenuAction other) => label.compareTo(other.label);
|
||||
|
||||
bool operator >(MenuAction other) {
|
||||
return compareTo(other) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
class MorePopIcon extends StatelessWidget {
|
||||
final ValueChanged<MenuAction> onTapItem;
|
||||
const MorePopIcon({super.key, required this.onTapItem});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton<MenuAction>(
|
||||
itemBuilder: _buildItem,
|
||||
onSelected: onTapItem,
|
||||
icon: const Icon(Icons.more_vert_outlined),
|
||||
position: PopupMenuPosition.under,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<PopupMenuEntry<MenuAction>> _buildItem(BuildContext context) {
|
||||
return MenuAction.values
|
||||
.map((MenuAction action) => PopupMenuItem<MenuAction>(
|
||||
height: 35,
|
||||
value: action,
|
||||
child: Center(
|
||||
child: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 6,
|
||||
children: [
|
||||
Text(action.label),
|
||||
Icon(action.iconData, size: 18),
|
||||
],
|
||||
)),
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
162
lib/10/search_anchor_demo.dart
Normal file
162
lib/10/search_anchor_demo.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SearchAnchorDemo extends StatefulWidget {
|
||||
const SearchAnchorDemo({super.key});
|
||||
|
||||
@override
|
||||
State<SearchAnchorDemo> createState() => _SearchAnchorDemoState();
|
||||
}
|
||||
|
||||
class _SearchAnchorDemoState extends State<SearchAnchorDemo> {
|
||||
Color? selectedColorSeed;
|
||||
List<ColorLabel> searchHistory = <ColorLabel>[];
|
||||
|
||||
Iterable<Widget> getHistoryList(SearchController controller) {
|
||||
return searchHistory.map(
|
||||
(ColorLabel color) => ListTile(
|
||||
leading: const Icon(Icons.history),
|
||||
title: Text(color.label),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.call_missed),
|
||||
onPressed: () {
|
||||
controller.text = color.label;
|
||||
controller.selection = TextSelection.collapsed(offset: controller.text.length);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<Widget> getSuggestions(SearchController controller) {
|
||||
final String input = controller.value.text;
|
||||
return ColorLabel.values.where((ColorLabel color) => color.label.contains(input)).map(
|
||||
(ColorLabel filteredColor) => ListTile(
|
||||
leading: CircleAvatar(backgroundColor: filteredColor.color),
|
||||
title: Text(filteredColor.label),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.call_missed),
|
||||
onPressed: () {
|
||||
controller.text = filteredColor.label;
|
||||
controller.selection = TextSelection.collapsed(offset: controller.text.length);
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
controller.closeView(filteredColor.label);
|
||||
handleSelection(filteredColor);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void handleSelection(ColorLabel selectedColor) {
|
||||
setState(() {
|
||||
selectedColorSeed = selectedColor.color;
|
||||
if (searchHistory.length >= 5) {
|
||||
searchHistory.removeLast();
|
||||
}
|
||||
searchHistory.insert(0, selectedColor);
|
||||
});
|
||||
}
|
||||
|
||||
Map<String,Color> colorMaps(ColorScheme colors) => {
|
||||
'primary':colors.primary ,
|
||||
'secondary':colors.secondary ,
|
||||
'inverseSurface':colors.inverseSurface ,
|
||||
'background':colors.background ,
|
||||
|
||||
|
||||
'onPrimaryContainer':colors.onPrimaryContainer ,
|
||||
'onErrorContainer':colors.onErrorContainer ,
|
||||
'onBackground':colors.onBackground ,
|
||||
'onTertiaryContainer':colors.onTertiaryContainer ,
|
||||
|
||||
|
||||
'error':colors.error ,
|
||||
'inversePrimary':colors.inversePrimary ,
|
||||
'primaryContainer':colors.primaryContainer ,
|
||||
'errorContainer':colors.errorContainer ,
|
||||
|
||||
'onPrimary':colors.onPrimary ,
|
||||
'onSecondary':colors.onSecondary ,
|
||||
'onError':colors.onError ,
|
||||
'onTertiary':colors.onTertiary ,
|
||||
'onSurfaceVariant':colors.onSurfaceVariant ,
|
||||
'shadow':colors.shadow ,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData themeData = ThemeData(useMaterial3: true, colorSchemeSeed: selectedColorSeed);
|
||||
final ColorScheme colors = themeData.colorScheme;
|
||||
Map<String,Color> data = colorMaps(colors);
|
||||
SizedBox cardSize = const SizedBox(
|
||||
width: 80,
|
||||
height: 30,
|
||||
child: Text(''),
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('搜索颜色')),
|
||||
body: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
SearchAnchor.bar(
|
||||
barHintText: '输入颜色',
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
if (controller.text.isEmpty) {
|
||||
if (searchHistory.isNotEmpty) {
|
||||
return getHistoryList(controller);
|
||||
}
|
||||
return <Widget>[Center(child: Text('暂无历史记录.', style: TextStyle(color: colors.outline)))];
|
||||
}
|
||||
return getSuggestions(controller);
|
||||
},
|
||||
),
|
||||
cardSize,
|
||||
Wrap(
|
||||
children: data.keys.map((key) => Card(color: data[key], child: SizedBox(
|
||||
width: 80,
|
||||
height: 30,
|
||||
child: Center(child: Text(key,style: TextStyle(fontSize: 8,color: Colors.white,shadows: [
|
||||
BoxShadow(color: Colors.black,offset: Offset(.1,.1),blurRadius: 2)
|
||||
]),)),
|
||||
))).toList(),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum ColorLabel {
|
||||
red('red', Colors.red),
|
||||
orange('orange', Colors.orange),
|
||||
yellow('yellow', Colors.yellow),
|
||||
green('green', Colors.green),
|
||||
blue('blue', Colors.blue),
|
||||
indigo('indigo', Colors.indigo),
|
||||
violet('violet', Color(0xFF8F00FF)),
|
||||
purple('purple', Colors.purple),
|
||||
pink('pink', Colors.pink),
|
||||
silver('silver', Color(0xFF808080)),
|
||||
gold('gold', Color(0xFFFFD700)),
|
||||
beige('beige', Color(0xFFF5F5DC)),
|
||||
brown('brown', Colors.brown),
|
||||
grey('grey', Colors.grey),
|
||||
black('black', Colors.black),
|
||||
white('white', Colors.white);
|
||||
|
||||
const ColorLabel(this.label, this.color);
|
||||
final String label;
|
||||
final Color color;
|
||||
}
|
||||
5
lib/10/节点介绍.txt
Normal file
5
lib/10/节点介绍.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
app_info.dart: 弹出对话框界面
|
||||
cupertino_context_menu_demo.dart: 弹出 CupertinoContextMenu
|
||||
dropdown_button_color.dart: 弹出 DropdownButton
|
||||
more_pop_icon.dart: 弹出 PopupMenuButton
|
||||
search_anchor_demo.dart: 弹出 SearchAnchor
|
||||
24
lib/11/color_detail.dart
Normal file
24
lib/11/color_detail.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorDetailPage extends StatelessWidget {
|
||||
final Color color;
|
||||
const ColorDetailPage({super.key, required this.color});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: color,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
iconTheme: IconThemeData(color: Colors.white),
|
||||
titleTextStyle: TextStyle(color: Colors.white,fontSize: 16,fontWeight: FontWeight.bold),
|
||||
backgroundColor: color,
|
||||
title: Text('颜色详情页'),
|
||||
),
|
||||
body: Center(
|
||||
child: Text( '#${color.value.toRadixString(16)}',style: TextStyle(color: Colors.white,fontSize: 26,fontWeight: FontWeight.bold),),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
66
lib/11/color_page.dart
Normal file
66
lib/11/color_page.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../common/components/colors_panel.dart';
|
||||
import 'color_detail.dart';
|
||||
import 'transition.dart';
|
||||
|
||||
class ColorPage extends StatefulWidget {
|
||||
const ColorPage({super.key});
|
||||
|
||||
@override
|
||||
State<ColorPage> createState() => _ColorPageState();
|
||||
}
|
||||
|
||||
class _ColorPageState extends State<ColorPage> {
|
||||
final List<Color> _colors = [
|
||||
Colors.red,
|
||||
Colors.black,
|
||||
Colors.blue,
|
||||
Colors.green,
|
||||
Colors.orange,
|
||||
Colors.pink,
|
||||
Colors.purple,
|
||||
Colors.indigo,
|
||||
Colors.amber,
|
||||
Colors.cyan,
|
||||
Colors.redAccent,
|
||||
Colors.grey,
|
||||
Colors.blueAccent,
|
||||
Colors.greenAccent,
|
||||
Colors.orangeAccent,
|
||||
Colors.pinkAccent,
|
||||
Colors.purpleAccent,
|
||||
Colors.indigoAccent,
|
||||
Colors.amberAccent,
|
||||
Colors.cyanAccent,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('颜色主页')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _toAddPage,
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: ColorsPanel(
|
||||
colors: _colors,
|
||||
onSelect: _selectColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor(Color color) {
|
||||
Route route = PageRouteBuilder<void>(
|
||||
barrierColor: Colors.white,
|
||||
pageBuilder: (_, __, ___) => ColorDetailPage(color:color),
|
||||
transitionsBuilder: kSlideBottomToTopWithSecondary,
|
||||
);
|
||||
Navigator.push(context, route);
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(builder: (_)=>ColorDetailPage(color:color)));
|
||||
}
|
||||
|
||||
void _toAddPage() {
|
||||
}
|
||||
}
|
||||
72
lib/11/main.dart
Normal file
72
lib/11/main.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:iroute/11/transition.dart';
|
||||
|
||||
import 'color_page.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
supportedLocales: const [
|
||||
Locale('zh', 'CN'),
|
||||
],
|
||||
locale: const Locale('zh', 'CN'),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const HomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Cose 酷色"),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: _toColorHome,
|
||||
child: Text('打开颜色界面'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _toColorHome() {
|
||||
Route route = PageRouteBuilder<void>(
|
||||
barrierColor: Colors.white,
|
||||
pageBuilder: (_, __, ___) => const ColorPage(),
|
||||
transitionsBuilder: kSlideBottomToTopWithSecondary,
|
||||
);
|
||||
Navigator.push(context, route);
|
||||
// Navigator.pushReplacement(context, route);
|
||||
|
||||
}
|
||||
}
|
||||
22
lib/11/transition.dart
Normal file
22
lib/11/transition.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
RouteTransitionsBuilder kSlideBottomToTopWithSecondary = (
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child,
|
||||
) {
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0.0, 1.0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: const Offset(0.0, 1.0),
|
||||
).animate(secondaryAnimation),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
};
|
||||
1
lib/11/节点介绍.txt
Normal file
1
lib/11/节点介绍.txt
Normal file
@@ -0,0 +1 @@
|
||||
路由第二动画控制器效果演示
|
||||
@@ -1,11 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'pages/app/app.dart';
|
||||
|
||||
|
||||
void main() {
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
|
||||
import 'pages/app.dart';
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
setHashUrlStrategy();
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/parser.dart';
|
||||
import '../route/route_state.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
State<App> createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> {
|
||||
late final RootRouterDelegate _delegate;
|
||||
late final AppRouteParser _parser;
|
||||
late final RouteState _routeState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_parser = AppRouteParser(initialRoute: '/color', allowPaths: [
|
||||
'/color',
|
||||
'/color/add',
|
||||
'/color/detail/:colorHex',
|
||||
]);
|
||||
_routeState = RouteState(_parser);
|
||||
_delegate = RootRouterDelegate(_routeState);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RouteStateScope(
|
||||
notifier: _routeState,
|
||||
child: MaterialApp.router(
|
||||
routerDelegate: _delegate,
|
||||
routeInformationParser: _parser,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
appBarTheme: const AppBarTheme(
|
||||
elevation: 0,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
))),
|
||||
debugShowCheckedModeBanner: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorAddPage extends StatefulWidget {
|
||||
const ColorAddPage({super.key});
|
||||
|
||||
@override
|
||||
State<ColorAddPage> createState() => _ColorAddPageState();
|
||||
}
|
||||
|
||||
class _ColorAddPageState extends State<ColorAddPage> {
|
||||
late Color _color;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_color = randomColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String text = '# ${_color.value.toRadixString(16)}';
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('添加颜色'),
|
||||
actions: [IconButton(onPressed: _selectColor, icon: Icon(Icons.check ))],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0,vertical: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(text,style: TextStyle(color: _color,fontSize: 24,letterSpacing: 4),)),
|
||||
Container(
|
||||
margin: EdgeInsets.only(left: 10),
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: Icon(
|
||||
Icons.sell_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _color,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Random _random = Random();
|
||||
|
||||
Color get randomColor {
|
||||
return Color.fromARGB(
|
||||
255,
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor() {
|
||||
Navigator.of(context).pop(_color);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/route_state.dart';
|
||||
import 'color_add_page.dart';
|
||||
|
||||
import '../../../common/components/colors_panel.dart';
|
||||
import '../../../common/pages/stl_color_page.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
final List<Color> _colors = [
|
||||
Colors.red, Colors.black, Colors.blue, Colors.green, Colors.orange,
|
||||
Colors.pink, Colors.purple, Colors.indigo, Colors.amber, Colors.cyan,
|
||||
Colors.redAccent, Colors.grey, Colors.blueAccent, Colors.greenAccent, Colors.orangeAccent,
|
||||
Colors.pinkAccent, Colors.purpleAccent, Colors.indigoAccent, Colors.amberAccent, Colors.cyanAccent,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title:const Text('颜色主页')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _toAddPage,
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: ColorsPanel(
|
||||
colors: _colors,
|
||||
onSelect: _selectColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor(Color color){
|
||||
String value = '#${color.value.toRadixString(16)}';
|
||||
RouteStateScope.of(context).go('/color/detail/$value');
|
||||
}
|
||||
|
||||
void _toAddPage() async {
|
||||
RouteStateScope.of(context).go('/color/add');
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:quiver/core.dart';
|
||||
|
||||
/// A route path that has been parsed by [TemplateRouteParser].
|
||||
class ParsedRoute extends Equatable{
|
||||
/// The current path location without query parameters. (/book/123)
|
||||
final String path;
|
||||
|
||||
/// The path template (/book/:id)
|
||||
final String pathTemplate;
|
||||
|
||||
/// The path parameters ({id: 123})
|
||||
final Map<String, String> parameters;
|
||||
|
||||
/// The query parameters ({search: abc})
|
||||
final Map<String, String> queryParameters;
|
||||
|
||||
const ParsedRoute(this.path, this.pathTemplate, this.parameters, this.queryParameters);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [path,pathTemplate,parameters,queryParameters];
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/common/pages/stl_color_page.dart';
|
||||
import 'package:path_to_regexp/path_to_regexp.dart';
|
||||
import '../pages/home_page.dart';
|
||||
import '../pages/color_add_page.dart';
|
||||
import 'parsed_route.dart';
|
||||
import 'route_state.dart';
|
||||
|
||||
class AppRouteParser extends RouteInformationParser<ParsedRoute> {
|
||||
final List<String> allowPaths;
|
||||
final ParsedRoute initialRoute;
|
||||
|
||||
AppRouteParser({
|
||||
required this.allowPaths,
|
||||
String initialRoute = '/',
|
||||
}):initialRoute = ParsedRoute(initialRoute, initialRoute, {}, {});
|
||||
|
||||
@override
|
||||
Future<ParsedRoute> parseRouteInformation(
|
||||
RouteInformation routeInformation) async {
|
||||
print("=======parseRouteInformation:${routeInformation.uri.path}===================");
|
||||
|
||||
final uri = routeInformation.uri;
|
||||
final path = uri.toString();
|
||||
final queryParams = uri.queryParameters;
|
||||
|
||||
ParsedRoute parsedRoute = initialRoute;
|
||||
|
||||
for (var pathTemplate in allowPaths) {
|
||||
final parameters = <String>[];
|
||||
var pathRegExp = pathToRegExp(pathTemplate, parameters: parameters);
|
||||
if (pathRegExp.hasMatch(path)) {
|
||||
final match = pathRegExp.matchAsPrefix(path);
|
||||
if (match == null) continue;
|
||||
final params = extract(parameters, match);
|
||||
parsedRoute = ParsedRoute(path, pathTemplate, params, queryParams);
|
||||
}
|
||||
}
|
||||
return parsedRoute;
|
||||
}
|
||||
|
||||
@override
|
||||
RouteInformation? restoreRouteInformation(ParsedRoute configuration) {
|
||||
print("=======restoreRouteInformation:${configuration}===================");
|
||||
|
||||
return RouteInformation(uri: Uri.parse(configuration.path));
|
||||
}
|
||||
}
|
||||
|
||||
class RootRouterDelegate extends RouterDelegate<ParsedRoute>
|
||||
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
||||
|
||||
final RouteState routeState;
|
||||
|
||||
|
||||
RootRouterDelegate(this.routeState) {
|
||||
routeState.addListener(notifyListeners);
|
||||
}
|
||||
|
||||
@override
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
ParsedRoute get currentConfiguration {
|
||||
print("=======currentConfiguration:${routeState.route.path}===================");
|
||||
|
||||
return routeState.route;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
routeState.removeListener(notifyListeners);
|
||||
routeState.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
final _addColorKey = const ValueKey('addColor');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final routeState = RouteStateScope.of(context);
|
||||
List<Page> pages =[];
|
||||
final String pathTemplate = routeState.route.pathTemplate;
|
||||
|
||||
pages.add(MaterialPage(child: HomePage()));
|
||||
|
||||
String? selectedColor;
|
||||
if (pathTemplate == '/color/detail/:colorHex') {
|
||||
selectedColor = routeState.route.parameters['colorHex'];
|
||||
}
|
||||
|
||||
if(selectedColor!=null){
|
||||
pages.add(MaterialPage(child: StlColorPage(
|
||||
color: Colors.redAccent,
|
||||
)));
|
||||
}
|
||||
|
||||
bool isAddPage = pathTemplate == '/color/add';
|
||||
if(isAddPage){
|
||||
pages.add(MaterialPage(
|
||||
key: _addColorKey,
|
||||
child: ColorAddPage()));
|
||||
}
|
||||
print("===build====================");
|
||||
return Navigator(
|
||||
key: navigatorKey,
|
||||
pages: pages,
|
||||
onPopPage: (route, result) {
|
||||
print(result);
|
||||
if (route.settings is Page &&
|
||||
(route.settings as Page).key == _addColorKey) {
|
||||
routeState.go('/color');
|
||||
}
|
||||
// appState.selectedBook = null;
|
||||
// notifyListeners();
|
||||
return route.didPop(result);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 格式: /a /b
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(ParsedRoute configuration) async {
|
||||
print("===setNewRoutePath===${configuration}=================");
|
||||
routeState.route = configuration;
|
||||
return;
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<void> setInitialRoutePath( configuration) async{
|
||||
// _pages = [_pageMap['/']!];
|
||||
// notifyListeners();
|
||||
// }
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'parsed_route.dart';
|
||||
import 'parser.dart';
|
||||
|
||||
/// The current route state. To change the current route, call obtain the state
|
||||
/// using `RouteStateScope.of(context)` and call `go()`:
|
||||
///
|
||||
/// ```
|
||||
/// RouteStateScope.of(context).go('/book/2');
|
||||
/// ```
|
||||
class RouteState extends ChangeNotifier {
|
||||
final AppRouteParser _parser;
|
||||
ParsedRoute _route;
|
||||
|
||||
RouteState(this._parser) : _route = _parser.initialRoute;
|
||||
|
||||
ParsedRoute get route => _route;
|
||||
|
||||
set route(ParsedRoute route) {
|
||||
// Don't notify listeners if the path hasn't changed.
|
||||
if (_route == route) return;
|
||||
|
||||
_route = route;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> go(String route) async {
|
||||
this.route = await _parser
|
||||
.parseRouteInformation(RouteInformation(uri: Uri.parse(route)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides the current [RouteState] to descendant widgets in the tree.
|
||||
class RouteStateScope extends InheritedNotifier<RouteState> {
|
||||
const RouteStateScope({
|
||||
required super.notifier,
|
||||
required super.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static RouteState of(BuildContext context) =>
|
||||
context.dependOnInheritedWidgetOfExactType<RouteStateScope>()!.notifier!;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
|
||||
import 'pages/app.dart';
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
setHashUrlStrategy();
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/parser.dart';
|
||||
import '../route/route_state.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
State<App> createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> {
|
||||
late final RootRouterDelegate _delegate;
|
||||
late final AppRouteParser _parser;
|
||||
late final RouteState _routeState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_parser = AppRouteParser();
|
||||
_routeState = RouteState(_parser,initial: '/color');
|
||||
_delegate = RootRouterDelegate(_routeState);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RouteStateScope(
|
||||
notifier: _routeState,
|
||||
child: MaterialApp.router(
|
||||
routerDelegate: _delegate,
|
||||
routeInformationParser: _parser,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
appBarTheme: const AppBarTheme(
|
||||
elevation: 0,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
))),
|
||||
debugShowCheckedModeBanner: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorAddPage extends StatefulWidget {
|
||||
const ColorAddPage({super.key});
|
||||
|
||||
@override
|
||||
State<ColorAddPage> createState() => _ColorAddPageState();
|
||||
}
|
||||
|
||||
class _ColorAddPageState extends State<ColorAddPage> {
|
||||
late Color _color;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_color = randomColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String text = '# ${_color.value.toRadixString(16)}';
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('添加颜色'),
|
||||
actions: [IconButton(onPressed: _selectColor, icon: Icon(Icons.check ))],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0,vertical: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(text,style: TextStyle(color: _color,fontSize: 24,letterSpacing: 4),)),
|
||||
Container(
|
||||
margin: EdgeInsets.only(left: 10),
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: Icon(
|
||||
Icons.sell_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _color,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Random _random = Random();
|
||||
|
||||
Color get randomColor {
|
||||
return Color.fromARGB(
|
||||
255,
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor() {
|
||||
Navigator.of(context).pop(_color);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/route_state.dart';
|
||||
import 'color_add_page.dart';
|
||||
|
||||
import '../../../common/components/colors_panel.dart';
|
||||
import '../../../common/pages/stl_color_page.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
final List<Color> _colors = [
|
||||
Colors.red, Colors.black, Colors.blue, Colors.green, Colors.orange,
|
||||
Colors.pink, Colors.purple, Colors.indigo, Colors.amber, Colors.cyan,
|
||||
Colors.redAccent, Colors.grey, Colors.blueAccent, Colors.greenAccent, Colors.orangeAccent,
|
||||
Colors.pinkAccent, Colors.purpleAccent, Colors.indigoAccent, Colors.amberAccent, Colors.cyanAccent,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title:const Text('颜色主页')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _toAddPage,
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: ColorsPanel(
|
||||
colors: _colors,
|
||||
onSelect: _selectColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor(Color color){
|
||||
String value = color.value.toRadixString(16);
|
||||
RouteStateScope.of(context).go('/color/detail?color=$value');
|
||||
}
|
||||
|
||||
void _toAddPage() async {
|
||||
RouteStateScope.of(context).go('/color/add');
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:quiver/core.dart';
|
||||
|
||||
/// A route path that has been parsed by [TemplateRouteParser].
|
||||
class ParsedRoute extends Equatable{
|
||||
/// The current path location without query parameters. (/book/123)
|
||||
final String path;
|
||||
|
||||
/// The query parameters ({search: abc})
|
||||
final Map<String, String> queryParameters;
|
||||
|
||||
const ParsedRoute(this.path, this.queryParameters);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [path,queryParameters];
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/common/pages/stl_color_page.dart';
|
||||
import 'package:path_to_regexp/path_to_regexp.dart';
|
||||
import '../pages/home_page.dart';
|
||||
import '../pages/color_add_page.dart';
|
||||
import 'parsed_route.dart';
|
||||
import 'route_state.dart';
|
||||
|
||||
class AppRouteParser extends RouteInformationParser<ParsedRoute> {
|
||||
|
||||
@override
|
||||
Future<ParsedRoute> parseRouteInformation(
|
||||
RouteInformation routeInformation) async {
|
||||
print("=======parseRouteInformation:${routeInformation.uri.path}===================");
|
||||
|
||||
final uri = routeInformation.uri;
|
||||
final path = uri.toString();
|
||||
final queryParams = uri.queryParameters;
|
||||
|
||||
return ParsedRoute(path, queryParams);
|
||||
}
|
||||
|
||||
@override
|
||||
RouteInformation? restoreRouteInformation(ParsedRoute configuration) {
|
||||
print("=======restoreRouteInformation:${configuration}===================");
|
||||
|
||||
return RouteInformation(uri: Uri.parse(configuration.path));
|
||||
}
|
||||
}
|
||||
|
||||
class RootRouterDelegate extends RouterDelegate<ParsedRoute>
|
||||
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
||||
|
||||
final RouteState routeState;
|
||||
|
||||
|
||||
RootRouterDelegate(this.routeState) {
|
||||
routeState.addListener(notifyListeners);
|
||||
}
|
||||
|
||||
@override
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
ParsedRoute get currentConfiguration {
|
||||
print("=======currentConfiguration:${routeState.route.path}===================");
|
||||
|
||||
return routeState.route;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
routeState.removeListener(notifyListeners);
|
||||
routeState.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
final _addColorKey = const ValueKey('addColor');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final routeState = RouteStateScope.of(context);
|
||||
List<Page> pages =[];
|
||||
final String path = routeState.route.path;
|
||||
|
||||
pages.add(MaterialPage(child: HomePage()));
|
||||
|
||||
String? selectedColor;
|
||||
if (path.startsWith('/color/detail') ) {
|
||||
selectedColor = routeState.route.queryParameters['color'];
|
||||
}
|
||||
|
||||
if(selectedColor!=null){
|
||||
pages.add(MaterialPage(child: StlColorPage(
|
||||
color: Color(int.parse(selectedColor,radix: 16)),
|
||||
)));
|
||||
}
|
||||
|
||||
bool isAddPage = path == '/color/add';
|
||||
if(isAddPage){
|
||||
pages.add(MaterialPage(
|
||||
key: _addColorKey,
|
||||
child: ColorAddPage()));
|
||||
}
|
||||
|
||||
return Navigator(
|
||||
key: navigatorKey,
|
||||
pages: pages,
|
||||
onPopPage: (route, result) {
|
||||
if (route.settings is Page && (route.settings as Page).key == _addColorKey) {
|
||||
routeState.go('/color');
|
||||
}
|
||||
|
||||
if(selectedColor!=null){
|
||||
selectedColor = null;
|
||||
routeState.go('/color');
|
||||
}
|
||||
|
||||
return route.didPop(result);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 格式: /a /b
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(ParsedRoute configuration) async {
|
||||
print("===setNewRoutePath===${configuration}=================");
|
||||
routeState.route = configuration;
|
||||
return;
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<void> setInitialRoutePath( configuration) async{
|
||||
// _pages = [_pageMap['/']!];
|
||||
// notifyListeners();
|
||||
// }
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'parsed_route.dart';
|
||||
import 'parser.dart';
|
||||
|
||||
/// The current route state. To change the current route, call obtain the state
|
||||
/// using `RouteStateScope.of(context)` and call `go()`:
|
||||
///
|
||||
/// ```
|
||||
/// RouteStateScope.of(context).go('/book/2');
|
||||
/// ```
|
||||
class RouteState extends ChangeNotifier {
|
||||
final AppRouteParser _parser;
|
||||
ParsedRoute _route;
|
||||
|
||||
RouteState(this._parser,{String initial=''}) : _route = ParsedRoute(initial,{});
|
||||
|
||||
ParsedRoute get route => _route;
|
||||
|
||||
set route(ParsedRoute route) {
|
||||
// Don't notify listeners if the path hasn't changed.
|
||||
if (_route == route) return;
|
||||
|
||||
_route = route;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> go(String route) async {
|
||||
this.route = await _parser
|
||||
.parseRouteInformation(RouteInformation(uri: Uri.parse(route)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides the current [RouteState] to descendant widgets in the tree.
|
||||
class RouteStateScope extends InheritedNotifier<RouteState> {
|
||||
const RouteStateScope({
|
||||
required super.notifier,
|
||||
required super.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static RouteState of(BuildContext context) =>
|
||||
context.dependOnInheritedWidgetOfExactType<RouteStateScope>()!.notifier!;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
|
||||
import 'pages/app.dart';
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
setHashUrlStrategy();
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/parser.dart';
|
||||
import '../route/route_state.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
State<App> createState() => _AppState();
|
||||
}
|
||||
|
||||
AppRouteParser parser = AppRouteParser();
|
||||
AppRouterDelegate routerDelegate = AppRouterDelegate();
|
||||
|
||||
class _AppState extends State<App> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp.router(
|
||||
routerDelegate: routerDelegate,
|
||||
routeInformationParser: parser,
|
||||
// backButtonDispatcher: RootBackButtonDispatcher(),
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
appBarTheme: const AppBarTheme(
|
||||
elevation: 0,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
))),
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorAddPage extends StatefulWidget {
|
||||
const ColorAddPage({super.key});
|
||||
|
||||
@override
|
||||
State<ColorAddPage> createState() => _ColorAddPageState();
|
||||
}
|
||||
|
||||
class _ColorAddPageState extends State<ColorAddPage> {
|
||||
late Color _color;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_color = randomColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String text = '# ${_color.value.toRadixString(16)}';
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('添加颜色'),
|
||||
actions: [IconButton(onPressed: _selectColor, icon: Icon(Icons.check ))],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0,vertical: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(text,style: TextStyle(color: _color,fontSize: 24,letterSpacing: 4),)),
|
||||
Container(
|
||||
margin: EdgeInsets.only(left: 10),
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: Icon(
|
||||
Icons.sell_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _color,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Random _random = Random();
|
||||
|
||||
Color get randomColor {
|
||||
return Color.fromARGB(
|
||||
255,
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
_random.nextInt(256),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor() {
|
||||
Navigator.of(context).pop(_color);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../route/route_state.dart';
|
||||
import 'app.dart';
|
||||
import 'color_add_page.dart';
|
||||
|
||||
import '../../../common/components/colors_panel.dart';
|
||||
import '../../../common/pages/stl_color_page.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
final List<Color> _colors = [
|
||||
Colors.red, Colors.black, Colors.blue, Colors.green, Colors.orange,
|
||||
Colors.pink, Colors.purple, Colors.indigo, Colors.amber, Colors.cyan,
|
||||
Colors.redAccent, Colors.grey, Colors.blueAccent, Colors.greenAccent, Colors.orangeAccent,
|
||||
Colors.pinkAccent, Colors.purpleAccent, Colors.indigoAccent, Colors.amberAccent, Colors.cyanAccent,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title:const Text('颜色主页')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _toAddPage,
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: ColorsPanel(
|
||||
colors: _colors,
|
||||
onSelect: _selectColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectColor(Color color){
|
||||
String value = color.value.toRadixString(16);
|
||||
routerDelegate.go('/color/detail?color=$value');
|
||||
}
|
||||
|
||||
void _toAddPage() async {
|
||||
routerDelegate.go('/color/add');
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:quiver/core.dart';
|
||||
|
||||
/// A route path that has been parsed by [TemplateRouteParser].
|
||||
class ParsedRoute extends Equatable{
|
||||
/// The current path location without query parameters. (/book/123)
|
||||
final String path;
|
||||
|
||||
/// The query parameters ({search: abc})
|
||||
final Map<String, String> queryParameters;
|
||||
|
||||
const ParsedRoute(this.path, this.queryParameters);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [path,queryParameters];
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/common/pages/stl_color_page.dart';
|
||||
import 'package:path_to_regexp/path_to_regexp.dart';
|
||||
import '../pages/app.dart';
|
||||
import '../pages/home_page.dart';
|
||||
import '../pages/color_add_page.dart';
|
||||
import 'parsed_route.dart';
|
||||
import 'route_state.dart';
|
||||
|
||||
class AppRouteParser extends RouteInformationParser<ParsedRoute> {
|
||||
@override
|
||||
Future<ParsedRoute> parseRouteInformation(
|
||||
RouteInformation routeInformation) async {
|
||||
print("=======parseRouteInformation:${routeInformation.uri.path}===================");
|
||||
|
||||
final uri = routeInformation.uri;
|
||||
final path = uri.toString();
|
||||
final queryParams = uri.queryParameters;
|
||||
|
||||
return ParsedRoute(path, queryParams);
|
||||
}
|
||||
|
||||
@override
|
||||
RouteInformation? restoreRouteInformation(ParsedRoute configuration) {
|
||||
print("=======restoreRouteInformation:${configuration}===================");
|
||||
return RouteInformation(uri: Uri.parse(configuration.path));
|
||||
}
|
||||
}
|
||||
|
||||
class AppRouterDelegate extends RouterDelegate<ParsedRoute>
|
||||
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
||||
|
||||
AppRouterDelegate({String initial = '/'}) {
|
||||
_routes.add(ParsedRoute(initial, {}));
|
||||
}
|
||||
|
||||
final List<ParsedRoute> _routes = [];
|
||||
|
||||
@override
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
ParsedRoute get currentConfiguration {
|
||||
return _routes.last;
|
||||
}
|
||||
|
||||
Future<void> go(String route) async {
|
||||
ParsedRoute _route = await parser.parseRouteInformation(RouteInformation(uri: Uri.parse(route)));
|
||||
if(_route!=_routes.last){
|
||||
_routes.add(_route);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
final _addColorKey = const ValueKey('addColor');
|
||||
final _colorDetailKey = const ValueKey('ColorDetail');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Page> pages = [];
|
||||
|
||||
for (ParsedRoute route in _routes) {
|
||||
Page? page = _buildPageByPath(route);
|
||||
if(page!=null){
|
||||
pages.add(page);
|
||||
}
|
||||
}
|
||||
|
||||
return Navigator(
|
||||
key: navigatorKey,
|
||||
pages: pages,
|
||||
onPopPage: _onPagePop,
|
||||
);
|
||||
}
|
||||
|
||||
Page? _buildPageByPath(ParsedRoute route) {
|
||||
if(route.path == '/'){
|
||||
return MaterialPage(child: HomePage());
|
||||
}
|
||||
|
||||
if(route.path.startsWith('/color/detail')){
|
||||
String? selectedColor = route.queryParameters['color'];
|
||||
|
||||
if (selectedColor != null) {
|
||||
Color color = Color(int.parse(selectedColor, radix: 16));
|
||||
return MaterialPage(key: _colorDetailKey, child: StlColorPage(color: color));
|
||||
}
|
||||
}
|
||||
|
||||
if (route.path == '/color/add') {
|
||||
return MaterialPage(key: _addColorKey, child: ColorAddPage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(ParsedRoute configuration) async {
|
||||
print("===setNewRoutePath===${configuration}=================");
|
||||
if(configuration!=_routes.last){
|
||||
_routes.add(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
bool _onPagePop(Route route, result) {
|
||||
RouteSettings settings = route.settings;
|
||||
if(settings is Page){
|
||||
if(settings.key==_addColorKey){
|
||||
_routes.removeLast();
|
||||
notifyListeners();
|
||||
}
|
||||
if(settings.key==_colorDetailKey){
|
||||
_routes.removeLast();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
return route.didPop(result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'parsed_route.dart';
|
||||
import 'parser.dart';
|
||||
|
||||
/// The current route state. To change the current route, call obtain the state
|
||||
/// using `RouteStateScope.of(context)` and call `go()`:
|
||||
///
|
||||
/// ```
|
||||
/// RouteStateScope.of(context).go('/book/2');
|
||||
/// ```
|
||||
class RouteState extends ChangeNotifier {
|
||||
final AppRouteParser _parser;
|
||||
ParsedRoute _route;
|
||||
|
||||
RouteState(this._parser,{String initial=''}) : _route = ParsedRoute(initial,{});
|
||||
|
||||
ParsedRoute get route => _route;
|
||||
|
||||
set route(ParsedRoute route) {
|
||||
// Don't notify listeners if the path hasn't changed.
|
||||
if (_route == route) return;
|
||||
|
||||
_route = route;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> go(String route) async {
|
||||
this.route = await _parser
|
||||
.parseRouteInformation(RouteInformation(uri: Uri.parse(route)));
|
||||
}
|
||||
}
|
||||
|
||||
// /// Provides the current [RouteState] to descendant widgets in the tree.
|
||||
// class RouteStateScope extends InheritedNotifier<RouteState> {
|
||||
// const RouteStateScope({
|
||||
// required super.notifier,
|
||||
// required super.child,
|
||||
// super.key,
|
||||
// });
|
||||
//
|
||||
// static RouteState of(BuildContext context) =>
|
||||
// context.dependOnInheritedWidgetOfExactType<RouteStateScope>()!.notifier!;
|
||||
// }
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
import '../../main.dart';
|
||||
import 'app_tool_bar.dart';
|
||||
|
||||
class App extends StatelessWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
appBarTheme: const AppBarTheme(
|
||||
elevation: 0,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
))),
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: Scaffold(
|
||||
appBar: AppToolBar(),
|
||||
body: Router(routerDelegate: router),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../page_a.dart';
|
||||
import '../page_b.dart';
|
||||
import '../page_c.dart';
|
||||
import '../home_page.dart';
|
||||
|
||||
class AppRouterDelegate extends RouterDelegate<String> with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
||||
|
||||
AppRouterDelegate({String initial = '/'}):_path=initial;
|
||||
|
||||
String _path;
|
||||
|
||||
String get path=> _path;
|
||||
|
||||
void go(String path){
|
||||
_path = path;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Navigator(
|
||||
onPopPage: _onPopPage,
|
||||
pages: parserConfig(_path).map((e) => _pageMap[e]!).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
final Map<String, Page> _pageMap = const {
|
||||
'/': MaterialPage(child: HomePage()),
|
||||
'a': MaterialPage(child: PageA()),
|
||||
'b': MaterialPage(child: PageB()),
|
||||
'c': MaterialPage(child: PageC()),
|
||||
};
|
||||
|
||||
Widget buildNavigatorByConfig(String path) {
|
||||
return Navigator(
|
||||
onPopPage: _onPopPage,
|
||||
pages: parserConfig(path).map((e) => _pageMap[e]!).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
bool _onPopPage(Route route, result) {
|
||||
if(path.length>1){
|
||||
int last = path.lastIndexOf('/');
|
||||
_path = path.substring(0,last);
|
||||
if(_path.isEmpty) _path = '/';
|
||||
notifyListeners();
|
||||
}
|
||||
return route.didPop(result);
|
||||
}
|
||||
|
||||
@override
|
||||
GlobalKey<NavigatorState>? navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(String configuration) async{
|
||||
_path = configuration;
|
||||
}
|
||||
|
||||
List<String> parserConfig(String path){
|
||||
/// 例: /a/b/c 进栈 /,a,b,c 界面
|
||||
List<String> result = ['/'];
|
||||
if(path.startsWith('/')){
|
||||
path = path.substring(1);
|
||||
if(path.isNotEmpty){
|
||||
List<String> parts = path.split('/');
|
||||
result.addAll(parts);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
|
||||
class AppToolBar extends StatefulWidget implements PreferredSizeWidget{
|
||||
const AppToolBar({super.key});
|
||||
|
||||
@override
|
||||
State<AppToolBar> createState() => _AppToolBarState();
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
|
||||
class _AppToolBarState extends State<AppToolBar> {
|
||||
|
||||
TextEditingController _ctrl = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_changRoute();
|
||||
router.addListener(_changRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
router.removeListener(_changRoute);
|
||||
_ctrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _changRoute() {
|
||||
_ctrl.text=router.path;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
title : TextField(
|
||||
controller: _ctrl,
|
||||
onSubmitted: _onSubmitted,
|
||||
decoration: InputDecoration( //装饰
|
||||
filled: true, //填充
|
||||
fillColor: Color(0xffF3F6F9), //填充颜色
|
||||
constraints: BoxConstraints(maxHeight: 34), //约束信息
|
||||
contentPadding: EdgeInsets.only(top: -14,left: 10),
|
||||
border: UnderlineInputBorder( //边线信息
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
hintText: "请输入路由", //提示字
|
||||
hintStyle: TextStyle(fontSize: 14) //提示字样式
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onSubmitted(String value) {
|
||||
router.go(value);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../main.dart';
|
||||
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Color bgColor = Color(0xffCCFFCC);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: bgColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('主页起点'),
|
||||
backgroundColor: bgColor,
|
||||
),
|
||||
body: Center(child: ElevatedButton(
|
||||
onPressed: () => toPageA(context),
|
||||
child: const Text('Push A'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void toPageA(BuildContext context) {
|
||||
router.go('/a');
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../main.dart';
|
||||
|
||||
class PageA extends StatelessWidget {
|
||||
const PageA({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Color bgColor = Color(0xffCCFFFF);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: bgColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('A 界面'),
|
||||
backgroundColor: bgColor,
|
||||
),
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => toPageB(context),
|
||||
child: const Text('Push B'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void toPageB(BuildContext context) {
|
||||
// router.value = ['/', 'a', 'b'];
|
||||
router.go('/a/b');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../main.dart';
|
||||
|
||||
class PageB extends StatelessWidget {
|
||||
const PageB({super.key});
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Color bgColor = Color(0xffCCE5FF);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: bgColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('B 界面'),
|
||||
backgroundColor: bgColor,
|
||||
|
||||
),
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => toPageC(context),
|
||||
child: const Text('Push C'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void toPageC(BuildContext context){
|
||||
router.go('/a/b/c');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../main.dart';
|
||||
|
||||
class PageC extends StatelessWidget {
|
||||
const PageC({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Color bgColor = Color(0xffFFE6CC);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: bgColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('C 界面'),
|
||||
backgroundColor: bgColor,
|
||||
),
|
||||
body: Center(
|
||||
child: Text('到达终点'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'pages/app/app.dart';
|
||||
import 'pages/app/app_router_delegate.dart';
|
||||
|
||||
|
||||
AppRouterDelegate router = AppRouterDelegate();
|
||||
|
||||
void main() {
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'pages/app/app.dart';
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
runApp(const App());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import 'package:toly_menu/toly_menu.dart';
|
||||
|
||||
List<MenuData> menus = [
|
||||
MenuData(path: '/dashboard', label: '总览面板', children: [
|
||||
MenuData(path: '/dashboard/data_analyse', label: '数据分析', deep: 1),
|
||||
MenuData(path: '/dashboard/work_board', label: '工作台', deep: 1, children: [
|
||||
MenuData(path: '/dashboard/work_board/a', label: '第一工作区', deep: 2),
|
||||
MenuData(path: '/dashboard/work_board/b', label: '第二工作区', deep: 2),
|
||||
MenuData(path: '/dashboard/work_board/c', label: '第三工作区', deep: 2),
|
||||
]),
|
||||
]),
|
||||
MenuData(path: '/cases', label: '案例演示', children: [
|
||||
MenuData(path: '/cases/counter', label: '计数器项目', deep: 1),
|
||||
MenuData(path: '/cases/guess', label: '猜数字项目', deep: 1),
|
||||
MenuData(path: '/cases/muyu', label: '电子木鱼项目', deep: 1),
|
||||
MenuData(path: '/cases/canvas', label: '白板绘制项目', deep: 1),
|
||||
MenuData(path: '/cases/timer', label: '计时器项目', deep: 1),
|
||||
]),
|
||||
MenuData(path: '/manager', label: '系统管理', children: [
|
||||
MenuData(path: '/manager/account', label: '账号管理', deep: 1),
|
||||
MenuData(path: '/manager/role', label: '角色管理', deep: 1),
|
||||
MenuData(path: '/manager/menu', label: '菜单管理', deep: 1),
|
||||
]),
|
||||
MenuData(path: '/knowledge', label: '知识库管理', children: [
|
||||
MenuData(path: '/knowledge/a', label: '语文知识', deep: 1, children: [
|
||||
MenuData(
|
||||
path: '/knowledge/a/1',
|
||||
label: '诗词歌赋',
|
||||
deep: 2,
|
||||
),
|
||||
MenuData(
|
||||
path: '/knowledge/a/2',
|
||||
label: '人物故事',
|
||||
deep: 2,
|
||||
),
|
||||
MenuData(
|
||||
path: '/knowledge/a/3',
|
||||
label: '名著推荐',
|
||||
deep: 2,
|
||||
)
|
||||
]),
|
||||
MenuData(
|
||||
path: '/knowledge/b',
|
||||
label: '数学知识',
|
||||
children: [
|
||||
MenuData(
|
||||
path: '/knowledge/b/1',
|
||||
label: '人物故事',
|
||||
deep: 2,
|
||||
),
|
||||
MenuData(
|
||||
path: '/knowledge/b/2',
|
||||
label: '数学定理',
|
||||
deep: 2,
|
||||
),
|
||||
MenuData(
|
||||
path: '/knowledge/b/3',
|
||||
label: '几何知识',
|
||||
deep: 2,
|
||||
),
|
||||
MenuData(
|
||||
path: '/knowledge/b/4',
|
||||
label: '代数知识',
|
||||
deep: 2,
|
||||
)
|
||||
],
|
||||
deep: 1),
|
||||
MenuData(
|
||||
path: '/knowledge/c',
|
||||
label: '英语知识',
|
||||
deep: 1,
|
||||
),
|
||||
]),
|
||||
MenuData(path: '/widgets', label: '组件集录', children: [
|
||||
MenuData(path: '/widgets/stateless', label: '无状态组件', deep: 1),
|
||||
MenuData(path: '/widgets/stateful', label: '有状态组件', deep: 1),
|
||||
MenuData(path: '/widgets/single_child', label: '单子渲染组件', deep: 1),
|
||||
MenuData(path: '/widgets/mutli_child', label: '多子渲染组件', deep: 1),
|
||||
MenuData(path: '/widgets/sliver', label: '滑片组件', deep: 1),
|
||||
MenuData(path: '/widgets/proxy', label: '代理组件', deep: 1),
|
||||
MenuData(path: '/widgets/other', label: '其他组件', deep: 1),
|
||||
])
|
||||
];
|
||||
@@ -1,107 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:toly_menu/toly_menu.dart';
|
||||
|
||||
import '../../menus.dart';
|
||||
import '../../transition/fade_transition.dart';
|
||||
import 'root_content.dart';
|
||||
|
||||
class App extends StatelessWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
pageTransitionsTheme: PageTransitionsTheme(
|
||||
builders: {
|
||||
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
|
||||
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||
TargetPlatform.macOS: FadeUpwardsPageTransitionsBuilder(),
|
||||
TargetPlatform.windows: FadeTransitionsBuilder(),
|
||||
}
|
||||
),
|
||||
|
||||
appBarTheme: const AppBarTheme(
|
||||
elevation: 0,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
backgroundColor: Colors.white,
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
))),
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: AppLayout());
|
||||
}
|
||||
}
|
||||
|
||||
class AppLayout extends StatelessWidget {
|
||||
const AppLayout({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 210,
|
||||
child: MenuPanel(),
|
||||
),
|
||||
// Container()
|
||||
Expanded(child: RootContent())
|
||||
],
|
||||
),
|
||||
// appBar: AppToolBar(),
|
||||
// body: AppNavigation(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MenuPanel extends StatefulWidget {
|
||||
const MenuPanel({super.key});
|
||||
|
||||
@override
|
||||
State<MenuPanel> createState() => _MenuPanelState();
|
||||
}
|
||||
|
||||
class _MenuPanelState extends State<MenuPanel> {
|
||||
MenuState state = MenuState(expandMenus: ['/dashboard'], activeMenu: '/dashboard/data_analyse', items: menus);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TolyMenu(state: state, onSelect: _onSelect);
|
||||
}
|
||||
|
||||
void _onSelect(MenuData menu) {
|
||||
|
||||
|
||||
if(menu.isLeaf){
|
||||
state = state.copyWith(activeMenu: menu.path);
|
||||
print("menu.path:${menu.path}");
|
||||
goRouter.go(menu.path);
|
||||
}else{
|
||||
List<String> menus = [];
|
||||
String path = menu.path.substring(1);
|
||||
List<String> parts = path.split('/');
|
||||
|
||||
if(parts.isNotEmpty){
|
||||
String path = '';
|
||||
for (String part in parts) {
|
||||
path+='/$part';
|
||||
menus.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
if(state.expandMenus.contains(menu.path)){
|
||||
menus.remove(menu.path);
|
||||
}
|
||||
|
||||
state = state.copyWith(expandMenus: menus);
|
||||
|
||||
}
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:iroute/cases/cases.dart';
|
||||
|
||||
import '../color_page.dart';
|
||||
|
||||
// GoRouter configuration
|
||||
final goRouter = GoRouter(
|
||||
initialLocation: '/manager',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/dashboard',
|
||||
builder: (_,__)=>SizedBox(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'data_analyse',
|
||||
// builder: (context, state) => ColorPage(title: 'data_analyse',),
|
||||
pageBuilder: (context, state) {
|
||||
return CustomTransitionPage(
|
||||
key: state.pageKey,
|
||||
child: ColorPage(title: 'data_analyse',),
|
||||
transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
||||
// Change the opacity of the screen using a Curve based on the the animation's
|
||||
// value
|
||||
return FadeTransition(
|
||||
opacity:
|
||||
CurveTween(curve: Curves.easeInOutCirc).animate(animation),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: 'work_board',
|
||||
builder: (_,__)=>SizedBox(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'a',
|
||||
builder: (context, state) => ColorPage(title: '第一工作区',),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'b',
|
||||
builder: (context, state) => ColorPage(title: '第二工作区',),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'c',
|
||||
builder: (context, state) => ColorPage(title: '第三工作区',),
|
||||
),
|
||||
]
|
||||
),
|
||||
|
||||
]
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: '/cases',
|
||||
builder: (_,__)=>SizedBox(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'counter',
|
||||
builder: (context, state) => CounterPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'guess',
|
||||
builder: (context, state) => GuessPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'muyu',
|
||||
builder: (context, state) => ColorPage(title: '第三工作区',),
|
||||
), GoRoute(
|
||||
path: 'canvas',
|
||||
builder: (context, state) => Paper(),
|
||||
), GoRoute(
|
||||
path: 'muyu',
|
||||
builder: (context, state) => ColorPage(title: '第三工作区',),
|
||||
),
|
||||
]
|
||||
),
|
||||
GoRoute(
|
||||
path: '/manager', builder: (_,__)=>SizedBox(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'account',
|
||||
builder: (context, state) => ColorPage(title: 'account',),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'role',
|
||||
builder: (context, state) => ColorPage(title: 'role',),
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
class RootContent extends StatelessWidget {
|
||||
const RootContent({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
|
||||
return Router.withConfig(config: goRouter);
|
||||
}
|
||||
}
|
||||
|
||||
class RootContentDelegate extends RouterDelegate with ChangeNotifier,PopNavigatorRouterDelegateMixin{
|
||||
|
||||
|
||||
@override
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Navigator(
|
||||
key: navigatorKey,
|
||||
pages: [
|
||||
|
||||
],
|
||||
onPopPage: (route, result) {
|
||||
// appState.selectedBook = null;
|
||||
// notifyListeners();
|
||||
return route.didPop(result);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(configuration) {
|
||||
// TODO: implement setNewRoutePath
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorPage extends StatelessWidget {
|
||||
final String title;
|
||||
const ColorPage({super.key, required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(body: Center(child: Text(title)));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user