文章目录
- 前言
- 相关链接
- 初始化项目
- 设置键盘映射
- 建议使用AnLink链接物理机。
- 项目配置
- 日志打印
- 官方案例
- 添加依赖
- 主函数更换
- 添加最简单的按钮
- Flutter 项目结构
- Flutter项目入口
- Flutter的MyApp函数
- 更新视图
- 直接修改
- 浅拷贝父节点数据
- 思考
- 修改布局
- 子节点重构
- 子节点布局重构
- 多次扩展布局
- 设置颜色主题
前言
为了得到的得到Uniapp的上位替代,最近打算使用Flutter开发。一般开发需要3个UI框架,icons库+UI框架+统计图
相关链接
【Flutter – 基础】快速入门 Flutter
Flutter 中文文档
编写第一个 Flutter 应用
初始化项目
注意,后续的代码主要就是抄官方的案例来的
编写第一个 Flutter 应用
设置键盘映射
我习惯用vscode 的快捷键了,这里设置一下。
建议使用AnLink链接物理机。
项目配置
# 降低代码检验的标准,让我们更简单的使用dart
linter:rules:prefer_const_constructors: falseprefer_final_fields: falseuse_key_in_widget_constructors: falseprefer_const_literals_to_create_immutables: falseprefer_const_constructors_in_immutables: falseavoid_print: false
日志打印
日志打印使用[print]函数即可
print('hello flutter');
官方案例
添加依赖
在[pubspec.yaml]中添加
name: namer_app
description: A new Flutter project.publish_to: 'none' # Remove this line if you wish to publish to pub.devversion: 0.0.1+1environment:sdk: '>=2.19.4 <4.0.0'# 这个就是Flutter对应的第三方库了
dependencies:flutter:sdk: flutterenglish_words: ^4.0.0provider: ^6.0.0dev_dependencies:flutter_test:sdk: flutterflutter_lints: ^2.0.0flutter:uses-material-design: true
主函数更换
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return ChangeNotifierProvider(create: (context) => MyAppState(),child: MaterialApp(title: 'Namer App',theme: ThemeData(useMaterial3: true,colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),),home: MyHomePage(),),);}
}class MyAppState extends ChangeNotifier {var current = WordPair.random();
}class MyHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {var appState = context.watch<MyAppState>();return Scaffold(body: Column(children: [Text('A random idea:'),Text(appState.current.asLowerCase),],),);}
}
确保没有报错之后测试运行
添加最简单的按钮
return Scaffold(body: Column(children: [Text('A random idea str:'),Text(appState.current.asLowerCase),//添加新的按钮ElevatedButton(onPressed: () {print('button click');},child: Text('Next'))],),);
Flutter 项目结构
Flutter项目入口
Flutter的MyApp函数
MyApp就是项目的布局入口了,类似于Wpf/windows里面的窗口。标注这整个外部的容器的形状
详细的请看官方教程
目前看下来是单向数据流的向下数据流。在React和Vue中,都是自顶向下的数据流。什么是数据流呢?在我看来,就是数据改变自动触发,自动传递的就是数据流。
为什么一般都是向下数据流呢,因为我们认为,父节点的数据是先生成,范围广,更准确的。就好像是从上流的水往下流一样,可以更能保证整个项目的稳定行。如果是向上数据流的话,那随意添加一个子节点都可能导致父节点发送改动。如果是双向数据流的话,会导致数据流动的方向不明确,难以维护。
那子节点又是怎么通知父节点的呢?一般都是通过函数回调的形式,就是手动通知父节点。相当于需要更加繁琐,明确的操作来保证父节点的数据稳定。
更新视图
更新视图需要用到notifyListeners,这个是用于通知视图的方法。在React和WPF中都是手动通知的,在Vue中是自动通知的。手动通知的好处就是可以操控。
注意:Dark有自己的命名规范,class大驼峰,类名和方法名都是小驼峰。
将[MyAppState]进行修改
//可通知视图修改的类
class MyAppState extends ChangeNotifier {//这个就相当于成员变量var current = WordPair.random();//手动声明回调函数,理论上来说,最好通过函数显性修改父节点属性void getNext(){current = WordPair.random();// 手动通知刷新视图元素notifyListeners();}//手动通知void notify(){notifyListeners();}
}
直接修改
return Scaffold(body: Column(children: [Text('A random idea str:'),Text(appState.current.asLowerCase),//添加新的按钮ElevatedButton(onPressed: () {print('button click');//直接修改父节点属性appState.current = WordPair.random();//手动更新通知appState.notify();//上面两步等于下面一步,但是还是建议使用函数有限制的回调//appState.getNext();},child: Text('Next'))],),);
浅拷贝父节点数据
为了防止父节点的数据遭到随意的修改,我们这里使用浅拷贝来复刻父节点的数据
class MyHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {//拿到父节点,由于父节点是单例,所以不需要别名var appState = context.watch<MyAppState>();//为了解决复杂的代码逻辑,在函数开头拿到数据,而不是直接对父节点的数据进行修改//这里是浅拷贝,不是深拷贝var pair = appState.current;return Scaffold(body: Column(children: [Text('A random idea str:'),// Text(appState.current.asLowerCase),Text(pair.asLowerCase),//添加新的按钮ElevatedButton(onPressed: () {print('button click');//直接修改父节点属性// pair = WordPair.random();//手动更新通知// appState.notify();//上面是浅拷贝的修改,无法反馈到父节点appState.getNext();},child: Text('Next'))],),);}
}
思考
所以我们的节点应该都是这么挂的
- MyApp + MyAppState
- MyHomePage + appState=MyAppState,这里的appState都是向上一级的父节点属性
所以我现在的问题就是如果一个父节点挂载多个子节点,会如何。现在还不了解
修改布局
子节点重构
右键Text节点,Refactor->Extarct Flutter Widget
子节点布局重构
多次扩展布局
在Padding布局外侧添加Card布局
设置颜色主题
@overrideWidget build(BuildContext context) {final theme = Theme.of(context); // ← Add this.return Card(color: theme.colorScheme.primary, // ← And also this.child: Padding(padding: const EdgeInsets.all(20),child: Text(pair.asLowerCase),),);}