前言
主要记录我在开发这个小说网项目的使用的代码块,方便忘记之后复用和分析
配置
- 状态管理:Getx 以及一些工具类
- 网络请求:dio
- 缓存shared_preferences
- 路由管理:fluro
环境变量
清华镜像
1 2
| PUB_HOSTED_URL:https://mirrors.tuna.tsinghua.edu.cn/dart-pub FLUTTER_STORAGE_BASE_URL:https://mirrors.tuna.tsinghua.edu.cn/flutter
|
官方镜像
1 2 3
| window的用户直接将下面的添加到环境变量中 PUB_HOSTED_URL=https://pub.flutter-io.cn FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
|
代码分析
常用布局
- Container: 用于创建矩形的可视化元素,可以设置背景颜色、边框、内外边距等属性。
- Row: 在水平方向上排列子控件。
- Column: 在垂直方向上排列子控件。
- Flex: 在主轴方向上创建弹性空间,通常与
Row
或 Column
一起使用。
- Wrap: 在水平或垂直方向上自动换行排列子控件。
- Stack: 叠放子控件,可以使用
Positioned
控制子控件的位置。
- Align: 在父控件内对齐子控件,可以设置对齐的位置。
- Center: 将子控件放置在中心位置。
- Expanded: 在
Row
或 Column
中,将子控件拉伸填充剩余空间。
- GridView: 创建一个网格布局。
- ListView: 创建一个可滚动的线性列表布局。
- SingleChildScrollView: 创建一个可滚动的单一子控件布局。
- Spacer: 在
Row
或 Column
中创建一个占位符。
- CustomScrollView: 创建自定义的滚动视图。
- SliverList 和 SliverGrid: 在
CustomScrollView
中使用的滚动列表和网格布局。
- Flow: 类似于网格的方式排列子控件,支持设置子控件的宽高比。
- Table: 创建一个表格布局,适用于展示二维数据。
- AspectRatio: 调整子控件的宽高比。
- IntrinsicHeight 和 IntrinsicWidth: 通过最大高度或最大宽度来约束子控件。
- FractionallySizedBox: 将子控件的大小设置为父控件的一部分比例。
- LimitedBox: 限制子控件的最大尺寸。
- Baseline: 根据基线对齐子控件。
- Positioned: 在父控件中精确定位子控件。
- IndexedStack: 叠放子控件,并根据索引显示其中一个。
- AspectRatio: 调整子控件的宽高比。
- ConstrainedBox: 对子控件施加额外的限制条件。
- FractionallySizedBox: 将子控件的大小设置为父控件的一部分比例。
- LayoutBuilder: 根据父控件的尺寸构建子控件。
- Offstage: 控制子控件是否可见,但仍占用空间。
- OverflowBox: 允许子控件超出父控件的边界。
- SizedBox: 固定尺寸的盒子。
- Transform: 对子控件进行旋转、平移、缩放等变换操作。
Fluro
记录一下fluro的用法吧
第一步
1 2 3 4 5 6 7 8 9
| import 'package:fluro/fluro.dart'; // // 一些全局的类 class Global { // 路由 static FluroRouter router = new FluroRouter(); }
|
第二步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; // 页面 import 'package:fictionapp/pages/home/home_page.dart'; import 'package:fictionapp/pages/login/login_page.dart';
import '../pages/login/register_page.dart';
// 登录页 var loginHandler = Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) { return const LoginPage(); });
// 首页 var HomeHandler = Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) { return const HomePage(); });
var RegisterHandler = Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) { return const RegisterPage(); }, );
|
第三步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'handlers.dart';
class Routes { static String home = "/home"; static String login = "/login"; static String register = "/register";
static void configureRoutes(FluroRouter router) { router.notFoundHandler = Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) { print("ROUTE WAS NOT FOUND !!!"); return; }); // 首页 router.define(home, handler: HomeHandler); //登录 router.define(login, handler: loginHandler); //注册 router.define(register, handler: RegisterHandler); } }
|
初始化
1 2 3 4 5 6 7 8 9
| void main() { // 初始化路由 FluroRouter router = new FluroRouter(); Routes.configureRoutes(router); // 将初始化的路由放大全局组件中 Global.router = router; runApp(const Application());
}
|
1
| Global.router.navigateTo(context, "/register", transition: TransitionType.inFromRight); // 具体页面的应用
|
列表组件
- 列表最顶层的页面最好是构建 其余的全部打静止滚轮。
- 自动刷新详见分类页的写法
getX
这边收藏一篇文章 写的非常好
GetBuilder
界面层在需要使用状态的地方使用 GetBuilder 包裹,然后就可以使用 Controller 访问状态对象和操作状态方法了。其中GetBuilder只需要两个参数:
init:初始状态对象,在这里可以完成状态对象的初始化。
builder 方法:这个方法用于构建依赖状态的组件树,方法携带状态对象参数,因此下面的组件可以访问到状态对象。而且一旦状态对象通过 update 方法通知有更新时,依赖状态对象的组件就会被刷新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Widget build(BuildContext context) { return GetBuilder<CounterController>( init: CounterController(), builder: (controller) => Scaffold( appBar: AppBar( title: Text('GetX计数器'), ), body: Center( child: Text( '${controller.counter}', style: TextStyle( color: Colors.blue, fontSize: 24.0, ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { controller.increment(); }, ), ), ); }
|
以上代码有点问题,GetBuilder包住了整个Scaffold,我们没必要把不需要刷新的组件包住
可以改成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('GetX计数器'), ), body: Center( child: GetBuilder<CounterController>( init: CounterController(), builder: (_) => Text( '${CounterController.to.counter}', style: TextStyle( color: Colors.blue, fontSize: 24.0, ), ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { CounterController.to.increment(); }, ), );
|
当只包住需要刷新的Text组件时,按钮的点击方法和GetBuilder在同一个层级,没办法访问到buidler中的controller,这时候可以在controller中定义一个静态的别名方法
1
| static CounterController get to => Get.find();
|
直接通过CounterController.to就可以访问到,但是要用Get.find()的话必须要先用Get.put()
或者Get.LazyPut()
注册依赖,然后就可以通过CounterController.to全局访问了
原文地址:https://www.cnblogs.com/r1cardo/p/17289339.html
设计一个自定义背景的底部导航
使用 Container
包装 Expanded
,然后为 Container
设置背景颜色,以实现 “加入书架” 和 “缓存” 按钮在 BottomAppBar
中占满高度,使按钮垂直充满 BottomAppBar
且具有自定义背景颜色的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| return BottomAppBar( child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( child: TextButton( onPressed: () { }, child: Text( '加入书架', style: TextStyle( color: Colors.blue,
), ), ), ), Container( width: 130, color: Colors.blue, child: Expanded( child: TextButton( onPressed: () { }, child: Text( '免费阅读', style: TextStyle( color: const Color.fromARGB(255, 252, 252, 253),
), ), ), ), ), Expanded( child: TextButton( onPressed: () { }, child: Text( '缓存', style: TextStyle( color: Colors.blue,
), ), ), ), ], ), );
|
状态栏
全局设置 放在main方法
1 2 3 4 5
| WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( statusBarColor: Color.fromARGB(0, 255, 255, 255), ));
|
WidgetsFlutterBinding.ensureInitialized();
:这一行确保Flutter的绑定已经初始化。Flutter应用程序通常需要一些初始化工作,这个函数确保这些初始化工作已经完成。
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(...));
:这行代码用于设置系统UI的覆盖样式,特别是状态栏的样式。在这里,它将状态栏的颜色设置为透明,使状态栏变成透明的样式,通常用于全屏应用程序。
1
| SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
这个是隐藏,但是默认是黑色 需要调节
空安全
Dart的空安全是一种强类型语言特性,它有助于在编写代码时更好地处理可能为null的值。下面是一个关于Dart中使用空安全的String? fictionId的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void main() { String? fictionId;
print(fictionId);
fictionId = "123"; print(fictionId);
String nonNullValue = fictionId ?? "默认值"; print(nonNullValue);
if (fictionId != null) { print("fictionId有值:$fictionId"); } else { print("fictionId为空"); } }
|
在这个示例中,我们首先声明fictionId为可空类型(String?),它可以存储字符串或null。然后,我们演示了如何在不同情况下处理fictionId的值,包括条件运算符和if语句来检查是否为null。这有助于编写更安全的代码,避免空指针异常。
心得
- 关于ListView非常消耗性能会造成卡顿 所以一个页面最多放一个ListView就可以。
- 安装性能来说 优先考虑CustomScrollView()以及里面的的组件来搭建页面,方便快捷,性能明显提升。