当前位置: 首页 > news >正文

Flutter学习笔记(六)---状态管理、事件、路由、动画

共享状态管理

InheritedWidget

InheritedWidget可以实现跨组件数据的传递
定义一个共享数据的InheritedWidget,需要继承自InheritedWidget

在这里插入图片描述

import 'package:flutter/material.dart';
import 'dart:math';/// 创建一个继承InheritedWidget的子类
class YZCounterWidget extends InheritedWidget {// 1. 共享的数据final int counter;// 2. 构造方法YZCounterWidget({required super.child,this.counter = 0});// 3. 获取组件最近的当前InheritedWidgetstatic YZCounterWidget? of(BuildContext context) {/// 沿着Element树,找最近的YZCounterElement,从Element中取出Widget对象return context.dependOnInheritedWidgetOfExactType();}// 4. 决定要不要回调didChangeDependencies  方法bool updateShouldNotify(YZCounterWidget oldWidget) {return oldWidget.counter != counter;//true执行}
}main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> {int _counter = 109;Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("InheritedWidget使用"),backgroundColor: Colors.purpleAccent,),body: YZCounterWidget(counter: _counter,child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [YZHomeShowData01(),YZHomeShowData02(),],),),),floatingActionButton: FloatingActionButton(child: Icon(Icons.add),onPressed: (){setState(() {_counter++;});},),);}
}class YZHomeShowData01 extends StatefulWidget {const YZHomeShowData01({super.key});State<YZHomeShowData01> createState() => _YZHomeShowData01State();
}class _YZHomeShowData01State extends State<YZHomeShowData01> {void didChangeDependencies() {// TODO: implement didChangeDependenciessuper.didChangeDependencies();print("_YZHomeShowData01State执行了didChangeDependencies");}Widget build(BuildContext context) {int? counter = YZCounterWidget.of(context)?.counter;return Card(color: Colors.greenAccent,child: Text("当前计数是:$counter"),);}
}class YZHomeShowData02 extends StatelessWidget {const YZHomeShowData02({super.key});Widget build(BuildContext context) {int? counter = YZCounterWidget.of(context)?.counter;return Container(decoration: BoxDecoration(color: Colors.amberAccent,),child: Text("当前计数是:$counter"),);}
}

Provider

Provider的一般使用步骤:

  1. 创建自己需要共享的数据
  2. 在应用程序的顶层使用ChangeNotifierProvider
  3. 在其他位置使用 共享数据 即可

android studio生成get/set方法的快捷键:command+n

有两种方法,可以设置或者获取 共享数据:
Provider.ofConsumer
一般使用Consumer,因为如果使用的是Provider.of,则当改变的时候,整个build方法会重新执行

注意: 点击的时候,直接++,不需要加setState

onPressed: (){contextVM.counter++;
},

在这里插入图片描述

import 'package:flutter/material.dart';
import 'dart:math';import 'package:provider/provider.dart';/// 共享数据 with是混入,也就是非继承但是可以有ChangeNotifier所以的方法和属性
class YZCounterViewModel with ChangeNotifier{int _counter = 10;int get counter => _counter;set counter(int value) {_counter = value;/// 通知所有的监听者notifyListeners();}
}main() {runApp(// 单个的// ChangeNotifierProvider(//   create: (BuildContext context) {//     return YZCounterViewModel();//   },//   child: MyApp()// ),// 多个的MultiProvider(providers: [ChangeNotifierProvider(create: (BuildContext context) {return YZCounterViewModel();},),// 多个// ...],child: MyApp(),));
}class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("InheritedWidget使用"),backgroundColor: Colors.purpleAccent,),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [YZHomeShowData01(),YZHomeShowData02(),YZHomeShowData03(),],),),// 使用Consumer// floatingActionButton: Consumer<YZCounterViewModel> (//   builder: (context, contextVM, child){//     print("floatingActionButton builder 被执行");//     return FloatingActionButton(//             child: child,//             onPressed: (){//               // 不需要加 setState//               // setState(() {//               //   contextVM.counter++;//               // });//               contextVM.counter++;//             },//           );//   },//   child:  Icon(Icons.add),//放在这,是为了不被每次重建// )// 使用 SelectorfloatingActionButton: Selector<YZCounterViewModel, YZCounterViewModel> (builder: (context, contextVM, child){print("floatingActionButton builder 被执行");return FloatingActionButton(child: child,onPressed: (){// 不需要加 setState// setState(() {//   contextVM.counter++;// });contextVM.counter++;},);},selector: (buildContext, viewModel){return viewModel;},/// 是否需要重新构建shouldRebuild: (previous, next){return false;// 不需要重新构建},child:  Icon(Icons.add),//放在这,是为了不被每次重建));}
}class YZHomeShowData01 extends StatefulWidget {const YZHomeShowData01({super.key});State<YZHomeShowData01> createState() => _YZHomeShowData01State();
}class _YZHomeShowData01State extends State<YZHomeShowData01> {void didChangeDependencies() {// TODO: implement didChangeDependenciessuper.didChangeDependencies();print("_YZHomeShowData01State执行了didChangeDependencies");}Widget build(BuildContext context) {int counter = Provider.of<YZCounterViewModel>(context).counter;print("YZHomeShowData01-build");return Card(color: Colors.greenAccent,child: Text("当前计数是:$counter"),);}
}class YZHomeShowData02 extends StatelessWidget {const YZHomeShowData02({super.key});Widget build(BuildContext context) {int counter = Provider.of<YZCounterViewModel>(context).counter;print("YZHomeShowData02-build");return Container(decoration: BoxDecoration(color: Colors.amberAccent,),child: Text("当前计数是:$counter"),);}
}class YZHomeShowData03 extends StatelessWidget {const YZHomeShowData03({super.key});Widget build(BuildContext context) {print("YZHomeShowData03-build");return Container(decoration: BoxDecoration(color: Colors.redAccent,),child: Consumer<YZCounterViewModel>(builder: (context, viewModel, child) {print("YZHomeShowData03-Consumer-build");return Text("当前计数是:${viewModel.counter}");}));}
}

事件

在这里插入图片描述

import 'package:flutter/material.dart';
import 'dart:math';main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("事件学习"),backgroundColor: Colors.purpleAccent,),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [YZTouchPointer(),SizedBox(height: 20,),YZGestureWidget(),SizedBox(height: 20,),YZGesture2Widget(),])),);}
}class YZTouchPointer extends StatelessWidget {const YZTouchPointer({super.key});Widget build(BuildContext context) {return Listener(onPointerDown: (event){print("onPointerDown");print(event.position);// 相当于整个屏幕print(event.localPosition); // 相当于本身},onPointerMove: (event){print("onPointerMove");},onPointerUp: (event){print("onPointerUp");},onPointerCancel: (event){print("onPointerCancel");},child: Container(width: 200,height: 200,color: Colors.amber,),);}
}class YZGestureWidget extends StatelessWidget {const YZGestureWidget({super.key});Widget build(BuildContext context) {return GestureDetector(onTapDown: (event){print("onTapDown");print(event.localPosition);//相当于本控件的print(event.globalPosition);//全局的},onTap: (){print("onTap");},onTapUp: (event){print("onPoionTapUpnterUp");},onTapCancel: (){print("onTapCancel");},onDoubleTap: (){print("onDoubleTap");},onLongPress: (){print("onLongPress");},child: Container(width: 200,height: 200,color: Colors.greenAccent,),);}
}class YZGesture2Widget extends StatelessWidget {const YZGesture2Widget({super.key});Widget build(BuildContext context) {return Stack(alignment: Alignment.center,children: [GestureDetector(onTapDown: (detail) {print("detail1");},child: Container(width: 200,height: 200,color: Colors.blue,),),GestureDetector(onTapDown: (detail) {print("detail2");},child: Container(width: 100,height: 100,color: Colors.red,),),],);}
}

事件传递

不同组件件,事件如何传递

可以使用第三方库,比如 event_bus

event_bus使用步骤:

//  1. 创建一个全局的EventBus对象
final eventBus = EventBus();// 2. 发出事件
eventBus.fire("This is changed message");// 3. 监听事件
eventBus.on<String>().listen((data){setState(() {message = data;});
});

在这里插入图片描述

import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';main() => runApp(MyApp());//  1. 创建一个全局的EventBus对象
final eventBus = EventBus();class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("事件学习"),backgroundColor: Colors.purpleAccent,),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [YZDemoButton(),YZDemoText()])),);}
}class YZDemoButton extends StatelessWidget {const YZDemoButton({super.key});Widget build(BuildContext context) {return TextButton(onPressed: (){// 2. 发出事件eventBus.fire("This is changed message");},child: Text("This is a button"),style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.cyan)),);}
}class YZDemoText extends StatefulWidget {const YZDemoText({super.key});State<YZDemoText> createState() => _YZDemoTextState();
}class _YZDemoTextState extends State<YZDemoText> {String message = "This is a message";void initState() {// TODO: implement initStatesuper.initState();// 3. 监听事件eventBus.on<String>().listen((data){setState(() {message = data;});});}Widget build(BuildContext context) {return Text(message);}
}

路由

在这里插入图片描述

普通跳转:Navigator

在这里插入图片描述

push到下一个界面:

Future resule = Navigator.push(context,MaterialPageRoute(builder: (BuildContext context){return YZHomeDetailPage(message: "123");})
);// 监听pop返回的信息
resule.then((res){setState(() {this._backMessage = res;});
});

返回pop:

TextButton(onPressed: (){Navigator.of(context).pop("返回按钮携带的信息");
}, child: Text("返回按钮"))

fullscreenDialog: true是从下往上出现,默认false,左右出现

MaterialPageRoute(builder: (BuildContext context){return YZHomeDetailPage(message: "123");},fullscreenDialog: true)

自定义转场动画

Future resule = Navigator.push(context,PageRouteBuilder(pageBuilder: (context, animation1, animation2){return FadeTransition(opacity: animation1,child: YZHomeDetailPage(message: "123"));},)
);

使用Route跳转

注册路由:

return MaterialApp(home: YZHomePage(),routes: {"/about": (BuildContext context){return Yzhomeaboutview(message: "123",);}},);

使用路由跳转:

Navigator.of(context).pushNamed("/about")

当然,最好在被跳转页里面加上:
static const String routeName = "/about";
这样,定义为静态变量,不依赖对象,而且,只有一份,全局可用,不易写错

Route传值

传递过去:
Navigator.of(context).pushNamed(Yzhomeaboutview.routeName, arguments: "传入到关于的信息");

接收:
final String message = ModalRoute.of(context)?.settings.arguments as String;

当跳转的控制器初始化携带构造函数参数的时候

// 钩子函数onGenerateRoute: (RouteSettings settings){if (settings.name == "/detail") {return MaterialPageRoute(builder: (context){return YZHomeDetailPage(message: settings.arguments as String,);});}return null;},

尽量给个没有界面的Widget,以防没有某个Widget,报错

当然,将Route单独创建一个文件,并将所以路由字符串放进去比较好


动画

做动画的Widget,需要是StatefulWidget

Animation(抽象类)

抽象类,不直接使用

AnimationController(可以使用)

可以直接使用,AnimationController继承Animation

CurvedAnimation

设置动画执行的速率(先快后慢、先慢后快等 )

Tween

设置动画执行value的范围(0-1)

在这里插入图片描述

import 'dart:ffi';import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';main() => runApp(MyApp());//  1. 创建一个全局的EventBus对象
final eventBus = EventBus();class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp( home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> with SingleTickerProviderStateMixin{late AnimationController _controller;Animation<double>? _animation;Animation<double>? _sizeAnimation;void initState() {// TODO: implement initStatesuper.initState();_controller = AnimationController(vsync: this,duration: Duration(seconds: 1),// lowerBound: 0.1,// upperBound: 1.0);// 设置Curved(速率)_animation = CurvedAnimation(parent: _controller,curve: Curves.linear,);_sizeAnimation = Tween<double>(begin: 50.0, end: 150.0).animate(_animation! as Animation<double>);// 监听动画// 这个方法不要,因为会刷新所以内容,对性能不好// _controller.addListener((){//   setState(() {////   });// });// 监听动画的状态_controller.addStatusListener((AnimationStatus status){if (status == AnimationStatus.completed){_controller.reverse();} else if (status == AnimationStatus.dismissed) {_controller.forward();}});}void dispose() {_controller.dispose(); // 释放资源super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("动画"),backgroundColor: Colors.purpleAccent,),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedBuilder(animation: _controller,builder: (BuildContext context, Widget? child) {return Icon(Icons.favorite,color: Colors.red,size: _sizeAnimation?.value,);//;},)],)),floatingActionButton: FloatingActionButton(child: Icon(Icons.refresh),onPressed: (){if (_controller.isAnimating) {_controller.stop();}else {if (_controller.status == AnimationStatus.forward) {_controller.forward();}else if (_controller.status == AnimationStatus.reverse) {_controller.reverse();}else {_controller.forward();}}}), //);}
}

交织动画

即,多个动画一起执行

在这里插入图片描述

import 'dart:ffi';
import 'dart:math';import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';main() => runApp(MyApp());//  1. 创建一个全局的EventBus对象
final eventBus = EventBus();class MyApp extends StatelessWidget {MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: YZHomePage(),);}
}class YZHomePage extends StatefulWidget {State<YZHomePage> createState() => _YZHomePageState();
}class _YZHomePageState extends State<YZHomePage> with SingleTickerProviderStateMixin{late AnimationController _controller;Animation<double>? _animation;Animation<double>? _sizeAnimation;Animation<Color>? _colorAnimation;Animation<double>? _opacityAnimation;Animation<double>? _radianAnimation;void initState() {// TODO: implement initStatesuper.initState();_controller = AnimationController(vsync: this,duration: Duration(seconds: 1),);// 设置Curved(速率)_animation = CurvedAnimation(parent: _controller,curve: Curves.linear,);_sizeAnimation = Tween<double>(begin : 50.0, end: 150.0).animate(_controller) as Animation<double>;//_colorAnimation = ColorTween(begin: Colors.lime, end: Colors.red).animate(_controller) as Animation<Color>;_opacityAnimation = Tween<double>(begin : 0.0, end: 1.0).animate(_controller) as Animation<double>;_radianAnimation = Tween<double>(begin : 0.0, end: 1.0).animate(_controller) as Animation<double>;// 监听动画的状态_controller.addStatusListener((AnimationStatus status){if (status == AnimationStatus.completed){_controller.reverse();} else if (status == AnimationStatus.dismissed) {_controller.forward();}});}void dispose() {_controller.dispose(); // 释放资源super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("动画"),backgroundColor: Colors.purpleAccent,),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedBuilder(animation: _controller,builder: (BuildContext context, Widget? child){return Transform(transform: Matrix4.rotationZ(_radianAnimation?.value ?? 0.0),alignment: Alignment.center,child: Container(width: _sizeAnimation?.value,height: _sizeAnimation?.value,color: Colors.blue.withOpacity(_opacityAnimation?.value ?? 0.5),),);},)],)),floatingActionButton: FloatingActionButton(child: Icon(Icons.refresh),onPressed: (){if (_controller.isAnimating) {_controller.stop();}else {if (_controller.status == AnimationStatus.forward) {_controller.forward();}else if (_controller.status == AnimationStatus.reverse) {_controller.reverse();}else {_controller.forward();}}}), //);}
}

颜色的切换没有写对


Hero

即,点击图片大图展示

在这里插入图片描述

主要是这两行代码:

Hero(tag: imageUrl,child: Image.network(imageUrl))

Hero例子代码:

import 'package:flutter/material.dart';
import 'dart:math';import 'package:learn_flutter/Animation/image_detail.dart';main() => runApp(MyApp());class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return const MaterialApp(home: YZHomePage(),);}
}class YZHomeButtonPage extends StatelessWidget {const YZHomeButtonPage({super.key});Widget build(BuildContext context) {return const Placeholder();}
}class YZHomePage extends StatelessWidget {const YZHomePage({super.key});Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Widget布局"),backgroundColor: Colors.purpleAccent,),body: YZHomeGridViewContent(),);}
}class YZHomeGridViewContent extends StatefulWidget {const YZHomeGridViewContent({super.key});State<YZHomeGridViewContent> createState() => _YZHomeGridViewContentState();
}class _YZHomeGridViewContentState extends State<YZHomeGridViewContent> {Widget build(BuildContext context) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 8),// 左右边框8间距child: GridView(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2,// 一行3个childAspectRatio: 1.5,// 宽1 高0.5crossAxisSpacing: 10, // 交叉轴间距(这里是左右间距)8mainAxisSpacing: 5,//主轴间距(在这里是上下间距)),children: List.generate(100, (index){final imageUrl = "https://picsum.photos/500/500?random=$index";return GestureDetector(onTap: (){Navigator.of(context).push(PageRouteBuilder(pageBuilder: (context, animation1, animation2){return FadeTransition(opacity: animation1,child: YZImageDetailPage(imageUrl: imageUrl));}));},child: Hero(tag: imageUrl,child: Image.network(imageUrl, fit: BoxFit.fitWidth,)));}) ),);}
}

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';class YZImageDetailPage extends StatelessWidget {final String imageUrl;const YZImageDetailPage({super.key,this.imageUrl = ""});Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.black,body: Center(child: GestureDetector(onTap: (){Navigator.of(context).pop();},child: Hero(tag: imageUrl,child: Image.network(imageUrl))),),);}
}
http://www.dtcms.com/a/325286.html

相关文章:

  • 达梦自定义存储过程实现获取表完整的ddl语句
  • Python FastAPI + React + Nginx 阿里云WINDOWS ECS部署实战:从标准流程到踩坑解决全记录
  • 爬虫与数据分析结和
  • NEON性能优化总结
  • Spring MVC 注解参数接收详解:@RequestBody、@PathVariable 等区别与使用场景
  • EXISTS 替代 IN 的性能优化技巧
  • 大数据量下分页查询性能优化实践(SpringBoot+MyBatis-Plus)
  • 基于Spring Data Elasticsearch的分布式全文检索与集群性能优化实践指南
  • Rust:anyhow 高效错误处理库核心用法详解
  • Rust 实战五 | 配置 Tauri 应用图标及解决 exe 被识别为威胁的问题
  • 新人该如何将不同的HTML、CSS、Javascript等文件转化为Vue3文件架构
  • 零基础学习jQuery第三天
  • 探秘华为:松山湖的科技与浪漫之旅
  • SQL 基础查询语句详解
  • DDIA第五章:分布式数据复制中的一致性与冲突处理
  • 基于STM32设计的矿山环境监测系统(NBIOT)_262
  • (25.08)Ubuntu20.04复现KISS-ICP
  • 【TensorRT踩坑记录】安装与使用
  • 软考 系统架构设计师系列知识点之杂项集萃(121)
  • 数据变而界面僵:Vue/React/Angular渲染失效解析与修复指南
  • leetcode-hot-100 (图论)
  • 算法训练营DAY57 第十一章:图论part07
  • 基于Qt Property Browser的通用属性系统:Any类与向量/颜色属性的完美结合
  • CVE-2019-0708复刻
  • react+vite-plugin-react-router-generator自动化生成路由
  • OBOO鸥柏丨115寸商用屏/工业液晶显示器招标投标核心标底参数要求
  • 【JAVA】使用系统音频设置播放音频
  • MyBatis执行器与ORM特性深度解析
  • React18 Transition特性详解
  • ARM汇编