当前位置: 首页 > 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.xdnf.cn/news/1283329.html

相关文章:

  • MCU 软件断点注意事项!!!
  • LVPECL、LVDS、LVTTL、LVCMOS四种逻辑电平标准的全面对比
  • C# 异步编程(BeginInvoke和EndInvoke)
  • GPT-5 全面解析与最佳实践指南
  • python面向对象设计模式
  • Linux DNS服务解析原理与搭建
  • OrbStack 入门教程:macOS 上的轻量级容器与虚拟机管理工具
  • C#高级语法_泛型
  • Vue 中的 Class 与 Style 绑定详解2
  • 基于 Spring Boot 的登录功能实现详解
  • 企业高性能 Web 服务部署实践(基于 RHEL 9)
  • sqli-labs通关笔记-第42关 POST字符型堆叠注入(单引号闭合 手工注入+脚本注入两种方法)
  • Rust学习笔记(一)|Rust初体验 猜数游戏
  • 从 GPT-2 到 gpt-oss:架构进步分析
  • 【lucene】文档id docid
  • 算法基础 1
  • 基于飞算JavaAI的日志监测系统开发实践:从智能生成到全链路落地
  • Spring-Security-5.7.11升级6.5.2
  • 机器学习-决策树(DecisionTree)
  • YOLOv6深度解析:实时目标检测的新突破
  • GESP2023年9月认证C++一级( 第三部分编程题(1)买文具)
  • vue3-pinia
  • 在 Ubuntu 中docker容器化操作来使用新建的 glibc-2.32
  • SQL 基础查询语句详解
  • Pytest项目_day12(yield、fixture的优先顺序)
  • 论文学习22:UNETR: Transformers for 3D Medical Image Segmentation
  • MFC C++ 使用ODBC方式调用Oracle数据库的详细步骤
  • 北京朝阳区中小学生信息学竞赛选拔赛C++真题
  • 电子电气架构 --- 软件定义汽车的驱动和挑战
  • [Element-plus]动态设置组件的语言