24
BIN
assets/images/anima.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/bg.jpeg
Normal file
|
After Width: | Height: | Size: 16 KiB |
43
assets/images/boy.svg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/images/draw.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/images/dream.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/dst.png
Normal file
|
After Width: | Height: | Size: 467 KiB |
BIN
assets/images/first.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/flutter.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/icon_head.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
assets/images/layout.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/rain.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/images/regex.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/render.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/right_chat.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/images/scroll.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/shoot.png
Normal file
|
After Width: | Height: | Size: 573 KiB |
BIN
assets/images/src.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
assets/images/sword.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
728
assets/images/t.svg
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
assets/images/touch.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/images/wy_200x300.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
assets/images/wy_300x200.jpg
Normal file
|
After Width: | Height: | Size: 61 KiB |
@@ -5,13 +5,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
|
import 'navigation/app_navigation.dart';
|
||||||
import 'v12/app.dart';
|
import 'v12/app.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
setSize();
|
setSize();
|
||||||
GoRouter.optionURLReflectsImperativeAPIs = true;
|
GoRouter.optionURLReflectsImperativeAPIs = true;
|
||||||
runApp(UnitApp());
|
runApp(TolyBooksApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ void setSize() async{
|
|||||||
if(kIsWeb||Platform.isAndroid||Platform.isIOS) return;
|
if(kIsWeb||Platform.isAndroid||Platform.isIOS) return;
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
WindowOptions windowOptions = const WindowOptions(
|
WindowOptions windowOptions = const WindowOptions(
|
||||||
size: Size(800, 540),
|
size: Size(1024, 1024*3/4),
|
||||||
minimumSize: Size(600, 400),
|
minimumSize: Size(600, 400),
|
||||||
center: true,
|
center: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
|||||||
113
lib/navigation/app_navigation.dart
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:iroute/components/components.dart';
|
||||||
|
import 'package:toly_menu/src/menu.dart';
|
||||||
|
import 'package:toly_menu/src/model/menu_state.dart';
|
||||||
|
import 'package:toly_menu/toly_menu.dart';
|
||||||
|
|
||||||
|
import '../v12/app/navigation/transition/fade_page_transitions_builder.dart';
|
||||||
|
import 'router/menus/menu_tree.dart';
|
||||||
|
import 'views/top_logo.dart';
|
||||||
|
import 'views/top_bar.dart';
|
||||||
|
import 'package:iroute/navigation/router/routers/app.dart';
|
||||||
|
|
||||||
|
class TolyBooksApp extends StatelessWidget {
|
||||||
|
final GoRouter _router = GoRouter(
|
||||||
|
initialLocation: '/dashboard/view',
|
||||||
|
routes: <RouteBase>[appRoute],
|
||||||
|
onException: (BuildContext ctx, GoRouterState state, GoRouter router) {
|
||||||
|
router.go('/404', extra: state.uri.toString());
|
||||||
|
},
|
||||||
|
// redirect: _authRedirect
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp.router(
|
||||||
|
routerConfig: _router,
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
title: 'Flutter Demo',
|
||||||
|
theme: ThemeData(
|
||||||
|
fontFamily: "宋体",
|
||||||
|
primarySwatch: Colors.blue,
|
||||||
|
pageTransitionsTheme: const PageTransitionsTheme(builders: {
|
||||||
|
TargetPlatform.android: ZoomPageTransitionsBuilder(),
|
||||||
|
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||||
|
TargetPlatform.macOS: FadePageTransitionsBuilder(),
|
||||||
|
TargetPlatform.windows: FadePageTransitionsBuilder(),
|
||||||
|
TargetPlatform.linux: FadePageTransitionsBuilder(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BookAppNavigation extends StatefulWidget {
|
||||||
|
final Widget content;
|
||||||
|
const BookAppNavigation({super.key, required this.content});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BookAppNavigation> createState() => _BookAppNavigationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BookAppNavigationState extends State<BookAppNavigation> {
|
||||||
|
MenuState state = MenuState(
|
||||||
|
expandMenus: ['/dashboard'],
|
||||||
|
activeMenu: '/dashboard/view',
|
||||||
|
items: rootMenu.children);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Row(
|
||||||
|
children: [
|
||||||
|
DragToMoveWrap(
|
||||||
|
child: Container(
|
||||||
|
color: const Color(0xff001529),
|
||||||
|
width: 210,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TopLogo(),
|
||||||
|
Expanded(child: TolyMenu(state: state, onSelect: _onSelect)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [AppTopBar(), Expanded(child: widget.content)],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSelect(MenuNode menu) {
|
||||||
|
if (menu.isLeaf) {
|
||||||
|
state = state.copyWith(activeMenu: menu.path);
|
||||||
|
print(menu.path);
|
||||||
|
// print(;
|
||||||
|
context.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(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
78
lib/navigation/router/menus/anima.dart
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
Map<String,dynamic> animaMenus = {
|
||||||
|
'path' : '/anima',
|
||||||
|
'label' : '动画-流光幻影',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.欢迎来到 Flutter 动画世界',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.基于文字的组件动画初体验',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.全面认识 AnimationController 的使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.认知和自定义 Curve 动画曲线',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.认识和自定义 Tween 补间动画',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.通过三个案例巩固练习动画使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.通过 loading 绘制练习动画使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.Flutter 内置动画组件-显式动画',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.显式动画 AnimatedWidget 源码解读',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.Flutter 内置动画组件-隐式动画',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.隐式动画 ImplicitlyAnimatedWidget 源码解读',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.Flutter 内置动画组件 - 其他动画',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.Flutter 框架层动画相关类源码分析',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.Flutter 框架层动画相关类关系梳理',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.AnimationController 源码解读',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter16',
|
||||||
|
'label' : '16.Ticker 与 TickerProvider 源码解读',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter17',
|
||||||
|
'label' : '17.小试牛刀 - 秒表功能和界面分析',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter18',
|
||||||
|
'label' : '18.使用 Ticker 驱动钟表运动',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
90
lib/navigation/router/menus/draw.dart
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
Map<String, dynamic> drawMenus = {
|
||||||
|
'path': '/draw',
|
||||||
|
'label': '绘制-妙笔生花',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path': '/chapter1',
|
||||||
|
'label': '1.纯粹的世界',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter2',
|
||||||
|
'label': '2.认识画笔的属性',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter3',
|
||||||
|
'label': '3.画布绘制基础操作',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter4',
|
||||||
|
'label': '4.画布绘制图片文字',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter5',
|
||||||
|
'label': '5.路径的图形添加',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter6',
|
||||||
|
'label': '6.路径的操作方法',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter7',
|
||||||
|
'label': '7.熟悉而陌生的颜色',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter8',
|
||||||
|
'label': '8.着色器和过滤器',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter9',
|
||||||
|
'label': '9.世界之基-CustomPainter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter10',
|
||||||
|
'label': '10.绘制中使用动画',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter11',
|
||||||
|
'label': '11.动画器曲线和方法',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter12',
|
||||||
|
'label': '12.手势在绘制中的使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter13',
|
||||||
|
'label': '13.Path 与曲线拟合',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter14',
|
||||||
|
'label': '14.认知贝塞尔曲线',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter15',
|
||||||
|
'label': '15.使用贝塞尔曲线',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter16',
|
||||||
|
'label': '16.简单统计图表绘制',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter17',
|
||||||
|
'label': '17.复杂图表绘制',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter18',
|
||||||
|
'label': '18.粒子物理运动',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter19',
|
||||||
|
'label': '19.粒子背景效果',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter20',
|
||||||
|
'label': '20.粒子时钟',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chapter21',
|
||||||
|
'label': '21.[番外]数学中的角度知识',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
90
lib/navigation/router/menus/dream.dart
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
Map<String,dynamic> dreamMenus = {
|
||||||
|
'path' : '/dream',
|
||||||
|
'label' : '基础-梦始之地',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.欢迎来到 Flutter 梦始之地',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.白话引言: 语言、框架和应用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.白话引言: 状态、行为和逻辑',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.学会说话 - 语句和量的定义',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.封装基础 - 函数方法的定义',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.万物基石 - 基本数据类型',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.逻辑桥梁 - 流程控制语句',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.逻辑血肉 - 运算符的使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.面向对象 - 定义与使用类',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.面向对象 - 类与类间关系',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.面向对象 - 封装、继承和多态',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.面向对象 - 抽象、接口和混入',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.语法集锦 - 类型相关其他语法',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.语法集锦 - 语言相关其他语法',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.梦始之地 - 计数器项目分析',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter16',
|
||||||
|
'label' : '16.梦始之地 - 组件的概念与使用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter17',
|
||||||
|
'label' : '17.小试牛刀 - 秒表功能和界面分析',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter18',
|
||||||
|
'label' : '18.小试牛刀 - 界面交互与数据维护',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter19',
|
||||||
|
'label' : '19.状态管理 - 主题色与国际化切换',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter20',
|
||||||
|
'label' : '20.状态管理 - 局部构建和逻辑分离',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter21',
|
||||||
|
'label' : '21.结语 - 离开新手村,继续冒险吧,朋友!',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
70
lib/navigation/router/menus/layout.dart
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
Map<String,dynamic> layoutMenus = {
|
||||||
|
'path' : '/layout',
|
||||||
|
'label' : '布局-薪火相传',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.欢迎进入 Flutter 布局探索',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.从打破紧约束开始说起',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.认识常用组件下施加的约束',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.探索 Flex 对布局结构的划分',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.Flex、Wrap、Stack 组件属性梳理',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.常见单子布局组件作用分析',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.常见布局实践演练',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.探索约束传递与尺寸确定',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.探索单子布局组件源码实现(上)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.探索单子布局组件源码实现(下)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.探索 Flex、Wrap、Stack 源码实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.使用单子与多子自定义布局',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.使用 Flow 组件自定义布局',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.浮层 Overlay 的使用与定位',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.IntrinsicHeight 作用与源码实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter16',
|
||||||
|
'label' : '16.立于布局体系之上的风采',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
74
lib/navigation/router/menus/menu_tree.dart
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import 'package:toly_menu/toly_menu.dart';
|
||||||
|
|
||||||
|
import 'anima.dart';
|
||||||
|
import 'draw.dart';
|
||||||
|
import 'dream.dart';
|
||||||
|
import 'layout.dart';
|
||||||
|
import 'render.dart';
|
||||||
|
import 'scroll.dart';
|
||||||
|
import 'touch.dart';
|
||||||
|
|
||||||
|
Map<String, dynamic> root = {
|
||||||
|
'path': '',
|
||||||
|
'label': '',
|
||||||
|
'children': [
|
||||||
|
dashboard,
|
||||||
|
drawMenus,
|
||||||
|
layoutMenus,
|
||||||
|
dreamMenus,
|
||||||
|
animaMenus,
|
||||||
|
touchMenus,
|
||||||
|
scrollMenus,
|
||||||
|
renderMenus,
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, dynamic> dashboard = {
|
||||||
|
'path': '/dashboard',
|
||||||
|
'label': '面板总览',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path': '/view',
|
||||||
|
'label': '小册全集',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/chat',
|
||||||
|
'label': '读者交流',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path': '/a',
|
||||||
|
'label': '第一交流区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/b',
|
||||||
|
'label': '第二交流区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path': '/c',
|
||||||
|
'label': '第三交流区',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuNode get rootMenu => parser(root, -1, '');
|
||||||
|
|
||||||
|
MenuNode parser(Map<String, dynamic> data, int deep, String prefix) {
|
||||||
|
String path = data['path'];
|
||||||
|
String label = data['label'];
|
||||||
|
List<Map<String, dynamic>>? childrenMap = data['children'];
|
||||||
|
List<MenuNode> children = [];
|
||||||
|
if (childrenMap != null && childrenMap.isNotEmpty) {
|
||||||
|
for (int i = 0; i < childrenMap.length; i++) {
|
||||||
|
MenuNode cNode = parser(childrenMap[i], deep + 1, prefix + path);
|
||||||
|
children.add(cNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MenuNode(
|
||||||
|
path: prefix + path,
|
||||||
|
label: label,
|
||||||
|
deep: deep,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
74
lib/navigation/router/menus/render.dart
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
Map<String,dynamic> renderMenus = {
|
||||||
|
'path' : '/render',
|
||||||
|
'label' : '渲染-聚沙成塔',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.欢迎进入 Flutter 渲染机制',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.从 runApp 方法到三树首脑会晤',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.初识元素节点的挂载和三树成型',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.探索单子渲染对象、元素的数据结构',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.探索多子渲染对象、元素的数据结构',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.探索组合型组件、元素存在的意义',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.探索状态类 State 源码实现与价值',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.探索节点更新时的变与不变',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.探索多子元素更新和 Key 的作用',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.探索代理组件、元素的实现与价值',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.组件、元素、渲染对象关系梳理',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.探索 WidgetsBinding 的初始化',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.探索 BuildOwner 构建管理器',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.探索 PipelineOwner 渲染管线',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.探索 RenderObject 的绘制与布局',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter16',
|
||||||
|
'label' : '16.探索 Layer 树与 Scene 的构建',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter17',
|
||||||
|
'label' : '17.终结篇: 立于渲染机制之上的风采',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
78
lib/navigation/router/menus/scroll.dart
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
Map<String,dynamic> scrollMenus = {
|
||||||
|
'path' : '/scroll',
|
||||||
|
'label' : '滑动-珠联璧合',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.认知视口滑动的构成',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.从 ListView 的源码开始谈起',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.探索 BoxScrollView 与 ScrollView 组件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.探索 ScrollView 一族其他滑动组件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.Scrollable 与 Viewport 的珠联璧合',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.探索 Scrollable 组件成员属性',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.探索 ViewPort 组件成员属性',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.再探索 ScrollView 一族的实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.探索 Sliver 组件吸顶效果',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.探索 NestedScrollView 嵌套滑动',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.探索 SliverConstraints 滑块约束',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.探索滑动中加载和缓存的实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.探索 Sliver 一族组件的必要性',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.探索 PageView 源码实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.探索 SingleChildScrollView 源码实现',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter16',
|
||||||
|
'label' : '16.探索 Notification 通知机制',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter17',
|
||||||
|
'label' : '17.探索 ScrollableState 滑动处理逻辑',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter18',
|
||||||
|
'label' : '18.探索 ScrollableState 动画处理逻辑',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
70
lib/navigation/router/menus/touch.dart
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
Map<String,dynamic> touchMenus = {
|
||||||
|
'path' : '/touch',
|
||||||
|
'label' : '手势-执掌天下',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'path' : '/chapter1',
|
||||||
|
'label' : '1.手势探索开篇前言',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter2',
|
||||||
|
'label' : '2.认识 GestureDetector 各种默认手势',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter3',
|
||||||
|
'label' : '3.从弹簧绘制实现竖直拖拽手势',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter4',
|
||||||
|
'label' : '4.从图章绘制实践 tap 手势操作',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter5',
|
||||||
|
'label' : '5.从白板绘制实践 pan 手势操作',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter6',
|
||||||
|
'label' : '6.从矩阵变换实践 scale 手势操作',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter7',
|
||||||
|
'label' : '7.探索 GestureDetector 组件源码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter8',
|
||||||
|
'label' : '8.探索 RawGestureDetector 组件源码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter9',
|
||||||
|
'label' : '9.知识储备: 认识 GestureRecognizer 相关类',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter10',
|
||||||
|
'label' : '10.知识储备: 认识手势竞技相关类',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter11',
|
||||||
|
'label' : '11.探索单击手势 TapGestureRecognizer 源码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter12',
|
||||||
|
'label' : '12.探索双击手势 DoubleTapGestureRecognizer 源码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter13',
|
||||||
|
'label' : '13.漫画手势: 来场竞技吧',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter14',
|
||||||
|
'label' : '14.自定义实现 N 连击手势事件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter15',
|
||||||
|
'label' : '15.从 Listener 组件探索事件的源头',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path' : '/chapter18',
|
||||||
|
'label' : '18.使用 Ticker 驱动钟表运动',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
43
lib/navigation/router/routers/app.dart
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:iroute/v12/pages/empty/empty_panel.dart';
|
||||||
|
|
||||||
|
import '../../../navigation/app_navigation.dart';
|
||||||
|
import 'dashboard.dart';
|
||||||
|
import 'draw.dart';
|
||||||
|
|
||||||
|
|
||||||
|
final RouteBase appRoute = ShellRoute(
|
||||||
|
builder: (BuildContext context, GoRouterState state, Widget child) {
|
||||||
|
return BookAppNavigation(content: child);
|
||||||
|
},
|
||||||
|
routes: <RouteBase>[
|
||||||
|
dashboardRouters,
|
||||||
|
drawRouters,
|
||||||
|
// GoRoute(
|
||||||
|
// path: 'counter',
|
||||||
|
// builder: (BuildContext context, GoRouterState state) {
|
||||||
|
// return const CounterPage();
|
||||||
|
// }),
|
||||||
|
// sortRouters,
|
||||||
|
// GoRoute(
|
||||||
|
// path: 'user',
|
||||||
|
// builder: (BuildContext context, GoRouterState state) {
|
||||||
|
// return const UserPage();
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// GoRoute(
|
||||||
|
// path: 'settings',
|
||||||
|
// builder: (BuildContext context, GoRouterState state) {
|
||||||
|
// return const SettingPage();
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
GoRoute(
|
||||||
|
path: '/404',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
String msg = '无法访问: ${state.extra}';
|
||||||
|
return EmptyPanel(msg: msg);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
32
lib/navigation/router/routers/dashboard.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:iroute/pages/dashboard/chat_room.dart';
|
||||||
|
import 'package:iroute/pages/dashboard/view_books.dart';
|
||||||
|
|
||||||
|
final RouteBase dashboardRouters = GoRoute(
|
||||||
|
path: '/dashboard',
|
||||||
|
redirect: (_,state) {
|
||||||
|
if (state.fullPath == '/dashboard') {
|
||||||
|
return '/dashboard/view';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
routes: <RouteBase>[
|
||||||
|
GoRoute(
|
||||||
|
path: 'view',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const ViewBooks();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: 'chat/:roomId',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
String? roomId = state.pathParameters['roomId'];
|
||||||
|
return ChatRoom(
|
||||||
|
roomId: roomId,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
47
lib/navigation/router/routers/draw.dart
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:idraw/idraw.dart';
|
||||||
|
import 'package:iroute/pages/dashboard/chat_room.dart';
|
||||||
|
|
||||||
|
|
||||||
|
final RouteBase drawRouters = GoRoute(
|
||||||
|
path: '/draw',
|
||||||
|
redirect: (_,state) {
|
||||||
|
if (state.fullPath == '/draw') {
|
||||||
|
return '/draw/chapter1';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
routes: <RouteBase>[
|
||||||
|
GoRoute(
|
||||||
|
path: 'chapter1',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const P01Page();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: 'chapter2',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const P02Page();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: 'chapter3',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const P03Page();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: 'chapter4',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const P04Page();
|
||||||
|
},
|
||||||
|
), GoRoute(
|
||||||
|
path: 'chapter5',
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
return const P05Page();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
25
lib/navigation/views/top_bar.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../components/components.dart';
|
||||||
|
|
||||||
|
class AppTopBar extends StatelessWidget {
|
||||||
|
const AppTopBar({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return DragToMoveWrap(
|
||||||
|
child: const Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 20,),
|
||||||
|
// Text(
|
||||||
|
// '404 界面丢失',
|
||||||
|
// style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
||||||
|
// ),
|
||||||
|
Spacer(),
|
||||||
|
WindowButtons()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/navigation/views/top_logo.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TopLogo extends StatelessWidget {
|
||||||
|
const TopLogo({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0,vertical: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
FlutterLogo(),
|
||||||
|
const SizedBox(width: 8,),
|
||||||
|
Text(
|
||||||
|
'Flutter Books',
|
||||||
|
style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/pages/dashboard/chat_room.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ChatRoom extends StatelessWidget {
|
||||||
|
final String? roomId;
|
||||||
|
const ChatRoom({super.key, required this.roomId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text('id: ${roomId}',style: TextStyle(fontSize: 32)),
|
||||||
|
const SizedBox(height: 16,),
|
||||||
|
Text('交流区正在建设中...',style: TextStyle(fontSize: 32),),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
lib/pages/dashboard/view_book/book_cell.dart
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/src/gestures/events.dart';
|
||||||
|
|
||||||
|
import '../view_books.dart';
|
||||||
|
|
||||||
|
class BookCell extends StatefulWidget {
|
||||||
|
final BookInfo bookInfo;
|
||||||
|
const BookCell({super.key, required this.bookInfo});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BookCell> createState() => _BookCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BookCellState extends State<BookCell> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
onEnter: _onEnter,
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Center(child: ClipRRect(
|
||||||
|
child: Image.asset(widget.bookInfo.cover),
|
||||||
|
borderRadius:BorderRadius.circular(8)
|
||||||
|
))),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: Text(
|
||||||
|
'${widget.bookInfo.info}',
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 12, color: Color(0xff515767)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onEnter(PointerEnterEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
37
lib/pages/dashboard/view_book/title_group.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TitleGroup extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
const TitleGroup({super.key, required this.title});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
),
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 6,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
186
lib/pages/dashboard/view_books.dart
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'view_book/book_cell.dart';
|
||||||
|
import 'view_book/title_group.dart';
|
||||||
|
|
||||||
|
class BookInfo {
|
||||||
|
final String name;
|
||||||
|
final String path;
|
||||||
|
final String url;
|
||||||
|
final String price;
|
||||||
|
final String info;
|
||||||
|
final String cover;
|
||||||
|
|
||||||
|
BookInfo({
|
||||||
|
required this.name,
|
||||||
|
required this.path,
|
||||||
|
required this.url,
|
||||||
|
required this.price,
|
||||||
|
required this.info,
|
||||||
|
required this.cover,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BookInfo> kBooks = [
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter语言基础·梦始之地',
|
||||||
|
path: 'dream',
|
||||||
|
url: 'https://juejin.cn/book/6844733827617652750',
|
||||||
|
info: '从语法到思想,欢迎来到 Flutter 梦开始的地方',
|
||||||
|
cover: 'assets/images/dream.webp',
|
||||||
|
price: '3.5',
|
||||||
|
),
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter绘制指南·妙笔生花',
|
||||||
|
path: 'draw',
|
||||||
|
url: 'https://juejin.cn/book/6844733827265331214',
|
||||||
|
info: '带你见证 Flutter 的绘制之美,擦出创造的火花',
|
||||||
|
cover: 'assets/images/draw.webp',
|
||||||
|
price: '3.28',
|
||||||
|
),
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter布局探索·薪火相传',
|
||||||
|
path: 'layout',
|
||||||
|
url: 'https://juejin.cn/book/7075958265250578469',
|
||||||
|
info: '由浅入深,从源码探索 Flutter 布局原理',
|
||||||
|
cover: 'assets/images/layout.webp',
|
||||||
|
price: '3.5',
|
||||||
|
),
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter手势探索·执掌天下',
|
||||||
|
path: 'touch',
|
||||||
|
url: 'https://juejin.cn/book/6896378716427911181',
|
||||||
|
info: 'Flutter 手势探索,用你的手指,掌控着整个屏幕世界 ',
|
||||||
|
cover: 'assets/images/touch.webp',
|
||||||
|
price: '3.5',
|
||||||
|
),
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter滑动探索·珠联璧合',
|
||||||
|
path: 'scroll',
|
||||||
|
url: 'https://juejin.cn/book/6984685333312962573',
|
||||||
|
info: '从源码入手,带你深入探索 Flutter 滑动体系',
|
||||||
|
price: '3.5',
|
||||||
|
cover: 'assets/images/scroll.webp',
|
||||||
|
),
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter动画探索·流光幻影',
|
||||||
|
path: 'anima',
|
||||||
|
url: 'https://juejin.cn/book/6965102582473687071',
|
||||||
|
info: 'Flutter 动画探索,一起去见证 Flutter 动画的风采',
|
||||||
|
cover: 'assets/images/anima.webp',
|
||||||
|
price: '3.5',
|
||||||
|
),
|
||||||
|
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter渲染机制·聚沙成塔',
|
||||||
|
path: 'dream',
|
||||||
|
url: 'https://juejin.cn/book/7084139149673889805',
|
||||||
|
info: '全面探索框架源码,助你攀登九层之台,一览顶上风采',
|
||||||
|
price: '3.5',
|
||||||
|
cover: 'assets/images/render.webp',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
List<BookInfo> freeBooks = [
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter 入门教程',
|
||||||
|
path: 'first',
|
||||||
|
url: 'https://juejin.cn/book/7212822723330834487',
|
||||||
|
info: '以有趣的案例为基础,带你入门 Flutter 技术',
|
||||||
|
cover: 'assets/images/first.webp',
|
||||||
|
price: '0',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<BookInfo> projectBooks = [
|
||||||
|
BookInfo(
|
||||||
|
name: 'Flutter 实战:正则匹配应用',
|
||||||
|
path: 'regex',
|
||||||
|
url: 'https://juejin.cn/book/7161060514377203751',
|
||||||
|
info: '从思想分析到实践, Flutter 全平台玩转正则表达式',
|
||||||
|
cover: 'assets/images/regex.webp',
|
||||||
|
price: '0',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
class ViewBooks extends StatelessWidget {
|
||||||
|
const ViewBooks({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SliverGridDelegate gridDelegate =
|
||||||
|
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
|
maxCrossAxisExtent: 240,
|
||||||
|
mainAxisSpacing: 10,
|
||||||
|
mainAxisExtent: 280,
|
||||||
|
crossAxisSpacing: 10,
|
||||||
|
);
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: TitleGroup(title: 'Flutter 七剑合璧',),
|
||||||
|
),
|
||||||
|
|
||||||
|
SliverGrid(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(_, i) => BookCell(bookInfo:kBooks[i]),
|
||||||
|
childCount: kBooks.length,
|
||||||
|
),
|
||||||
|
gridDelegate: gridDelegate),
|
||||||
|
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: TitleGroup(title: 'Flutter 实战探索',),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
SliverGrid(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(_, i) => BookCell(bookInfo:projectBooks[i]),
|
||||||
|
childCount: projectBooks.length,
|
||||||
|
),
|
||||||
|
gridDelegate: gridDelegate),
|
||||||
|
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: TitleGroup(title: 'Flutter 免费小册',),
|
||||||
|
),
|
||||||
|
SliverGrid(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(_, i) => BookCell(bookInfo:freeBooks[i]),
|
||||||
|
childCount: freeBooks.length,
|
||||||
|
),
|
||||||
|
gridDelegate: gridDelegate),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// SliverGridDelegate gridDelegate = const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
|
// maxCrossAxisExtent: 240,
|
||||||
|
// mainAxisSpacing: 10,
|
||||||
|
// mainAxisExtent: 260,
|
||||||
|
// crossAxisSpacing: 10,
|
||||||
|
// );
|
||||||
|
// return GridView.builder(
|
||||||
|
// padding: EdgeInsets.all(10),
|
||||||
|
// gridDelegate: gridDelegate,
|
||||||
|
// itemBuilder: (_, i) {
|
||||||
|
// BookInfo bookInfo = kBooks[i];
|
||||||
|
// return Center(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.symmetric(horizontal: 10,vertical: 6),
|
||||||
|
// child: Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Expanded(child: Center(child: Image.asset(bookInfo.cover))),
|
||||||
|
// const SizedBox(height: 6,),
|
||||||
|
// Text('${bookInfo.name}',style: TextStyle(fontSize: 14,fontWeight: FontWeight.bold),),
|
||||||
|
// const SizedBox(height: 6,),
|
||||||
|
// Text('${bookInfo.info}',style: TextStyle(fontSize: 12,color: Color(0xff515767)),),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// itemCount: kBooks.length,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,21 +8,23 @@ class EmptyPanel extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Material(
|
||||||
child: Wrap(
|
child: Center(
|
||||||
spacing: 16,
|
child: Wrap(
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
spacing: 16,
|
||||||
direction: Axis.vertical,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
direction: Axis.vertical,
|
||||||
Icon(Icons.nearby_error,size: 64, color: Colors.redAccent),
|
children: [
|
||||||
Text(
|
Icon(Icons.nearby_error,size: 64, color: Colors.redAccent),
|
||||||
msg,
|
Text(
|
||||||
style: TextStyle(fontSize: 24, color: Colors.grey),
|
msg,
|
||||||
),
|
style: TextStyle(fontSize: 24, color: Colors.grey),
|
||||||
ElevatedButton(onPressed: (){
|
),
|
||||||
context.go('/');
|
ElevatedButton(onPressed: (){
|
||||||
}, child: Text('返回首页'))
|
context.go('/');
|
||||||
],
|
}, child: Text('返回首页'))
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
84
packages/idraw/lib/components/coordinate.dart
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// create by 张风捷特烈 on 2020/5/1
|
||||||
|
/// contact me by email 1981462002@qq.com
|
||||||
|
/// 说明:
|
||||||
|
@immutable
|
||||||
|
class Coordinate {
|
||||||
|
final double step;
|
||||||
|
final double strokeWidth;
|
||||||
|
final Color axisColor;
|
||||||
|
final Color gridColor;
|
||||||
|
|
||||||
|
Coordinate(
|
||||||
|
{this.step = 20,
|
||||||
|
this.strokeWidth = .5,
|
||||||
|
this.axisColor = Colors.blue,
|
||||||
|
this.gridColor = Colors.grey});
|
||||||
|
|
||||||
|
final Paint _gridPaint = Paint();
|
||||||
|
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(size.width / 2, size.height / 2);
|
||||||
|
_drawGrid(canvas, size);
|
||||||
|
_drawAxis(canvas, size);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawGrid(Canvas canvas, Size size) {
|
||||||
|
_gridPaint
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = .5
|
||||||
|
..color = Colors.grey;
|
||||||
|
_drawBottomRight(canvas, size);
|
||||||
|
canvas.save();
|
||||||
|
canvas.scale(1, -1); //沿x轴镜像
|
||||||
|
_drawBottomRight(canvas, size);
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
canvas.scale(-1, 1); //沿y轴镜像
|
||||||
|
_drawBottomRight(canvas, size);
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
canvas.scale(-1, -1); //沿原点镜像
|
||||||
|
_drawBottomRight(canvas, size);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawAxis(Canvas canvas, Size size) {
|
||||||
|
_gridPaint
|
||||||
|
..color = Colors.blue
|
||||||
|
..strokeWidth = 1.5;
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(-size.width / 2, 0), Offset(size.width / 2, 0), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(0, -size.height / 2), Offset(0, size.height / 2), _gridPaint);
|
||||||
|
canvas.drawLine(Offset(0, size.height / 2),
|
||||||
|
Offset(0 - 7.0, size.height / 2 - 10), _gridPaint);
|
||||||
|
canvas.drawLine(Offset(0, size.height / 2),
|
||||||
|
Offset(0 + 7.0, size.height / 2 - 10), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width / 2, 0), Offset(size.width / 2 - 10, 7), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width / 2, 0), Offset(size.width / 2 - 10, -7), _gridPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawBottomRight(Canvas canvas, Size size) {
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.height / 2 / step; i++) {
|
||||||
|
canvas.drawLine(Offset(0, 0), Offset(size.width / 2, 0), _gridPaint);
|
||||||
|
canvas.translate(0, step);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.width / 2 / step; i++) {
|
||||||
|
canvas.drawLine(Offset(0, 0), Offset(0, size.height / 2), _gridPaint);
|
||||||
|
canvas.translate(step , 0);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
164
packages/idraw/lib/components/coordinate_pro.dart
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
/// create by 张风捷特烈 on 2020/5/1
|
||||||
|
/// contact me by email 1981462002@qq.com
|
||||||
|
/// 说明:
|
||||||
|
@immutable
|
||||||
|
class Coordinate {
|
||||||
|
final double step;
|
||||||
|
final double strokeWidth;
|
||||||
|
final Color axisColor;
|
||||||
|
final Color gridColor;
|
||||||
|
final TextPainter _textPainter = TextPainter(textDirection: TextDirection.ltr);
|
||||||
|
|
||||||
|
Coordinate(
|
||||||
|
{this.step = 20,
|
||||||
|
this.strokeWidth = .5,
|
||||||
|
this.axisColor = Colors.blue,
|
||||||
|
this.gridColor = Colors.grey});
|
||||||
|
|
||||||
|
final Paint _gridPaint = Paint();
|
||||||
|
final Path _gridPath = Path();
|
||||||
|
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(size.width / 2, size.height / 2);
|
||||||
|
_drawGridLine(canvas, size);
|
||||||
|
_drawAxis(canvas, size);
|
||||||
|
_drawText(canvas, size);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawAxis(Canvas canvas, Size size) {
|
||||||
|
_gridPaint
|
||||||
|
..color = Colors.blue
|
||||||
|
..strokeWidth = 1.5;
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(-size.width / 2, 0), Offset(size.width / 2, 0), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(0, -size.height / 2), Offset(0, size.height / 2), _gridPaint);
|
||||||
|
canvas.drawLine(Offset(0, size.height / 2),
|
||||||
|
Offset(0 - 7.0, size.height / 2 - 10), _gridPaint);
|
||||||
|
canvas.drawLine(Offset(0, size.height / 2),
|
||||||
|
Offset(0 + 7.0, size.height / 2 - 10), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width / 2, 0), Offset(size.width / 2 - 10, 7), _gridPaint);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width / 2, 0), Offset(size.width / 2 - 10, -7), _gridPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawGridLine(Canvas canvas, Size size) {
|
||||||
|
_gridPaint
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = .5
|
||||||
|
..color = Colors.grey;
|
||||||
|
|
||||||
|
for (int i = 0; i < size.width / 2 / step; i++) {
|
||||||
|
_gridPath.moveTo(step * i, -size.height / 2 );
|
||||||
|
_gridPath.relativeLineTo(0, size.height);
|
||||||
|
|
||||||
|
_gridPath.moveTo(-step * i, -size.height / 2 );
|
||||||
|
_gridPath.relativeLineTo(0, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < size.height / 2 / step; i++) {
|
||||||
|
_gridPath.moveTo(-size.width / 2,step * i );
|
||||||
|
_gridPath.relativeLineTo(size.width,0 );
|
||||||
|
|
||||||
|
_gridPath.moveTo(-size.width / 2,-step * i, );
|
||||||
|
_gridPath.relativeLineTo(size.width,0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawPath(_gridPath, _gridPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawAxisText(Canvas canvas, String str,
|
||||||
|
{Color color = Colors.black, bool? x = false}) {
|
||||||
|
TextSpan text = TextSpan(
|
||||||
|
text: str,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: color,
|
||||||
|
));
|
||||||
|
|
||||||
|
_textPainter.text = text;
|
||||||
|
_textPainter.layout(); // 进行布局
|
||||||
|
Size size = _textPainter.size;
|
||||||
|
Offset offset = Offset.zero;
|
||||||
|
if (x == null) {
|
||||||
|
offset = Offset(-size.width*1.5, size.width*0.7);
|
||||||
|
} else if (x) {
|
||||||
|
offset = Offset(-size.width / 2, size.height / 2);
|
||||||
|
} else {
|
||||||
|
offset = Offset(size.height / 2, -size.height / 2 + 2);
|
||||||
|
}
|
||||||
|
_textPainter.paint(canvas, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawText(Canvas canvas, Size size) {
|
||||||
|
// y > 0 轴 文字
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.height / 2 / step; i++) {
|
||||||
|
if (step < 30 && i.isOdd || i == 0) {
|
||||||
|
canvas.translate(0, step);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var str = (i * step).toInt().toString();
|
||||||
|
_drawAxisText(canvas, str, color: Colors.green);
|
||||||
|
}
|
||||||
|
canvas.translate(0, step);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
// x > 0 轴 文字
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.width / 2 / step; i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
_drawAxisText(canvas, "O", color: Colors.black, x: null);
|
||||||
|
canvas.translate(step, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (step < 30 && i.isOdd) {
|
||||||
|
canvas.translate(step, 0);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var str = (i * step).toInt().toString();
|
||||||
|
_drawAxisText(canvas, str, color: Colors.green, x: true);
|
||||||
|
}
|
||||||
|
canvas.translate(step, 0);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
// y < 0 轴 文字
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.height / 2 / step; i++) {
|
||||||
|
if (step < 30 && i.isOdd || i == 0) {
|
||||||
|
canvas.translate(0, -step);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var str = (-i * step).toInt().toString();
|
||||||
|
_drawAxisText(canvas, str, color: Colors.green);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.translate(0, -step);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
// x < 0 轴 文字
|
||||||
|
canvas.save();
|
||||||
|
for (int i = 0; i < size.width / 2 / step; i++) {
|
||||||
|
if (step < 30 && i.isOdd || i == 0) {
|
||||||
|
canvas.translate(-step, 0);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var str = (-i * step).toInt().toString();
|
||||||
|
_drawAxisText(canvas, str, color: Colors.green, x: true);
|
||||||
|
}
|
||||||
|
canvas.translate(-step, 0);
|
||||||
|
}
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
119
packages/idraw/lib/components/demo_shower.dart
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class DemoShower extends StatefulWidget {
|
||||||
|
final List<Widget> demos;
|
||||||
|
const DemoShower({super.key, required this.demos});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DemoShower> createState() => _DemoShowerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DemoShowerState extends State<DemoShower> {
|
||||||
|
PageController _ctrl = PageController();
|
||||||
|
int _index = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
children: [
|
||||||
|
PageView(
|
||||||
|
controller: _ctrl,
|
||||||
|
children: widget.demos,
|
||||||
|
),
|
||||||
|
|
||||||
|
Positioned(
|
||||||
|
bottom: 20,
|
||||||
|
child: Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
children: [
|
||||||
|
TolyIconButton(
|
||||||
|
onTap: (){
|
||||||
|
_index= (_index-1)%widget.demos.length;
|
||||||
|
setState(() {
|
||||||
|
|
||||||
|
});
|
||||||
|
_ctrl.animateToPage(_index,curve: Curves.easeIn,duration: Duration(milliseconds: 200));
|
||||||
|
},
|
||||||
|
iconData: Icons.navigate_before,
|
||||||
|
size: 36,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
child: Text('第 ${_index+1}/${widget.demos.length} 页',style: TextStyle(fontSize: 16,color: Colors.grey),),
|
||||||
|
),
|
||||||
|
|
||||||
|
TolyIconButton(
|
||||||
|
onTap: (){
|
||||||
|
_index= (_index+1)%widget.demos.length;
|
||||||
|
setState(() {
|
||||||
|
|
||||||
|
});
|
||||||
|
_ctrl.animateToPage(_index,curve: Curves.easeIn,duration: Duration(milliseconds: 200));
|
||||||
|
},
|
||||||
|
size: 36,
|
||||||
|
iconData: Icons.navigate_next,
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TolyIconButton extends StatefulWidget {
|
||||||
|
final IconData iconData;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final double size;
|
||||||
|
const TolyIconButton({
|
||||||
|
super.key,
|
||||||
|
required this.iconData,
|
||||||
|
required this.size, required this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TolyIconButton> createState() => _TolyIconButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TolyIconButtonState extends State<TolyIconButton> {
|
||||||
|
bool _hover = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: widget.onTap,
|
||||||
|
child: MouseRegion(
|
||||||
|
onEnter: _onEnter,
|
||||||
|
onExit: _onExit,
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
child: Container(
|
||||||
|
width: widget.size,
|
||||||
|
height: widget.size,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _hover?Colors.grey.withOpacity(0.6):Colors.grey.withOpacity(0.5), shape: BoxShape.circle),
|
||||||
|
child: Icon(
|
||||||
|
widget.iconData,
|
||||||
|
size: 26,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onEnter(PointerEnterEvent event) {
|
||||||
|
setState(() {
|
||||||
|
_hover = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onExit(PointerExitEvent event) {
|
||||||
|
setState(() {
|
||||||
|
_hover = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/idraw/lib/p01/p01.dart
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export 'p01_page.dart';
|
||||||
19
packages/idraw/lib/p01/p01_page.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/src/gestures/events.dart';
|
||||||
|
import 'package:idraw/components/demo_shower.dart';
|
||||||
|
import 's01_page.dart' as s1;
|
||||||
|
import 's02_page.dart' as s2;
|
||||||
|
|
||||||
|
class P01Page extends StatelessWidget {
|
||||||
|
const P01Page({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const DemoShower(
|
||||||
|
demos: [
|
||||||
|
s1.Paper(),
|
||||||
|
s2.Paper(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
packages/idraw/lib/p01/s01_page.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class Paper extends StatelessWidget {
|
||||||
|
const Paper({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: CustomPaint( // 使用CustomPaint
|
||||||
|
painter: PaperPainter(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaperPainter extends CustomPainter {
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
// 创建画笔
|
||||||
|
final Paint paint = Paint();
|
||||||
|
// 绘制圆
|
||||||
|
canvas.drawCircle(Offset(100, 100), 10, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||||
|
}
|
||||||
40
packages/idraw/lib/p01/s02_page.dart
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Paper extends StatelessWidget {
|
||||||
|
const Paper({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: CustomPaint( // 使用CustomPaint
|
||||||
|
painter: PaperPainter(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaperPainter extends CustomPainter {
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
// 创建画笔
|
||||||
|
final Paint paint = Paint();
|
||||||
|
paint
|
||||||
|
..color = Colors.blue //颜色
|
||||||
|
..strokeWidth = 4 //线宽
|
||||||
|
..style = PaintingStyle.stroke; //模式--线型
|
||||||
|
|
||||||
|
//绘制线
|
||||||
|
canvas.drawLine(Offset(0, 0), Offset(100, 100), paint);
|
||||||
|
|
||||||
|
Path path = Path();
|
||||||
|
path.moveTo(100, 100);
|
||||||
|
path.lineTo(200, 0);
|
||||||
|
canvas.drawPath(path, paint..color = Colors.red);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawLine(Canvas canvas) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||||
|
}
|
||||||
1
packages/idraw/lib/p02/p02.dart
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export 'p02_page.dart';
|
||||||