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

网站建设公司哪个好一点深圳荷坳网站建设公司

网站建设公司哪个好一点,深圳荷坳网站建设公司,2021世界500强企业,网站备案最快几天前言 当前案例 Flutter SDK版本#xff1a;3.13.2 显式动画 Tween({this.begin,this.end}) 两个构造参数#xff0c;分别是 开始值 和 结束值#xff0c;根据这两个值#xff0c;提供了控制动画的方法#xff0c;以下是常用的#xff1b; controller.forward() : 向前…前言 当前案例 Flutter SDK版本3.13.2 显式动画 Tween({this.begin,this.end}) 两个构造参数分别是 开始值 和 结束值根据这两个值提供了控制动画的方法以下是常用的 controller.forward() : 向前执行 begin 到 end 的动画执行结束后处于end状态controller.reverse() : 反向当动画已经完成进行还原动画controller.reset() : 重置当动画已经完成进行还原注意这个是直接还原没有动画 使用方式一 使用 addListener() 和 setState() import package:flutter/material.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 使用 addListener() 和 setState() class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late Animationdouble animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);animation Tweendouble(begin: 50, end: 100).animate(controller)..addListener(() {setState(() {}); // 更新UI})..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(显式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [SizedBox(width: animation.value,height: animation.value,child: const FlutterLogo(),),ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(缩放),)],)],),),);} }使用方式二 AnimatedWidget解决痛点不需要再使用 addListener() 和 setState() import package:flutter/material.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 测试 AnimatedWidget class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late Animationdouble animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);animation Tweendouble(begin: 50, end: 100).animate(controller)..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(显式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedLogo(animation: animation),ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(缩放),)],)],),),);} }/// 使用 AnimatedWidget创建显式动画 /// 解决痛点不需要再使用 addListener() 和 setState() class AnimatedLogo extends AnimatedWidget {const AnimatedLogo({super.key, required Animationdouble animation}): super(listenable: animation);overrideWidget build(BuildContext context) {final animation listenable as Animationdouble;return Center(child: Container(margin: const EdgeInsets.symmetric(vertical: 10),width: animation.value,height: animation.value,child: const FlutterLogo(),),);} } 使用方式三 使用 内置的显式动画 widget 后缀是 Transition 的组件几乎都是 显式动画 widget import package:flutter/material.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 使用 内置的显式动画Widget class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late Animationdouble animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);animation Tweendouble(begin: 0.1, end: 1.0).animate(controller)..addListener(() {setState(() {}); // 更新UI})..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(显式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [/// 单个显示动画FadeTransition(opacity: animation,child: const SizedBox(width: 100,height: 100,child: FlutterLogo(),),),/// 多个显示动画 配合使用// FadeTransition( // 淡入淡出// opacity: animation,// child: RotationTransition( // 旋转// turns: animation,// child: ScaleTransition( // 更替// scale: animation,// child: const SizedBox(// width: 100,// height: 100,// child: FlutterLogo(),// ),// ),// ),// ),ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(淡入淡出),)],)],),),);} }使用方式四 AnimatedBuilder这种方式感觉是 通过逻辑 动态选择 Widget比如 flag ? widgetA : widgetB 官方解释 AnimatedBuilder 知道如何渲染过渡效果但 AnimatedBuilder 不会渲染 widget也不会控制动画对象。使用 AnimatedBuilder 描述一个动画是其他 widget 构建方法的一部分。如果只是单纯需要用可重复使用的动画定义一个 widget可参考文档简单使用 AnimatedWidget。 import package:flutter/material.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 测试 AnimatedBuilder class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late Animationdouble animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);animation Tweendouble(begin: 50, end: 100).animate(controller)..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(显式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [GrowTransition(animation: animation,child: const FlutterLogo()),ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(缩放),)],)],),),);} }class GrowTransition extends StatelessWidget {final Widget child;final Animationdouble animation;const GrowTransition({required this.child, required this.animation, super.key});overrideWidget build(BuildContext context) {return Center(child: AnimatedBuilder(animation: animation,builder: (context, child) {return SizedBox(width: animation.value,height: animation.value,child: child,);},child: child,),);} }使用方式五 CurvedAnimation 曲线动画一个Widget同时使用多个动画 import package:flutter/material.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 测试 动画同步使用 class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late Animationdouble animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);animation CurvedAnimation(parent: controller, curve: Curves.easeIn)..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(显式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedLogoSync(animation: animation),ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(缩放 淡入淡出),)],)],),),);} }/// 动画同步使用 class AnimatedLogoSync extends AnimatedWidget {AnimatedLogoSync({super.key, required Animationdouble animation}): super(listenable: animation);final Tweendouble _opacityTween Tweendouble(begin: 0.1, end: 1);final Tweendouble _sizeTween Tweendouble(begin: 50, end: 100);overrideWidget build(BuildContext context) {final animation listenable as Animationdouble;return Center(child: Opacity(opacity: _opacityTween.evaluate(animation),child: SizedBox(width: _sizeTween.evaluate(animation),height: _sizeTween.evaluate(animation),child: const FlutterLogo(),),),);} } 隐式动画 根据属性值变化为 UI 中的 widget 添加动作并创造视觉效果有些库包含各种各样可以帮你管理动画的widget这些widgets被统称为 隐式动画 或 隐式动画 widget。前缀是 Animated 的组件几乎都是 隐式动画 widget       import dart:math;import package:flutter/material.dart;class ImplicitAnimation extends StatefulWidget {const ImplicitAnimation({super.key});overrideStateImplicitAnimation createState() _ImplicitAnimationState(); }class _ImplicitAnimationState extends StateImplicitAnimation {double opacity 0;late Color color;late double borderRadius;late double margin;double randomBorderRadius() {return Random().nextDouble() * 64;}double randomMargin() {return Random().nextDouble() * 32;}Color randomColor() {return Color(0xFFFFFFFF Random().nextInt(0xFFFFFFFF));}overridevoid initState() {super.initState();color randomColor();borderRadius randomBorderRadius();margin randomMargin();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(隐式动画,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [Row(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedOpacity(opacity: opacity,curve: Curves.easeInOutBack,duration: const Duration(milliseconds: 1000),child: Container(width: 50,height: 50,margin: const EdgeInsets.only(right: 12),color: Colors.primaries[2],),),ElevatedButton(onPressed: () {if(opacity 0) {opacity 1;} else {opacity 0;}setState(() {});},child: const Text(淡入或淡出),)],),Row(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedContainer(width: 50,height: 50,margin: EdgeInsets.all(margin),decoration: BoxDecoration(color: color,borderRadius: BorderRadius.circular(borderRadius)),curve: Curves.easeInBack,duration: const Duration(milliseconds: 1000),),ElevatedButton(onPressed: () {color randomColor();borderRadius randomBorderRadius();margin randomMargin();setState(() {});},child: const Text(形状变化),)],)],),),);}}显示和隐式的区别 看图隐式动画 就是 显示动画 封装后的产物是不是很蒙这有什么意义 应用场景不同如果想 控制动画使用 显示动画controller.forward()、controller.reverse()、controller.reset()反之只是在Widget属性值发生改变进行UI过渡这种简单操作使用 隐式动画 误区 Flutter显式动画的关键对象 Tween翻译过来 补间联想到 Android原生的补间动画就会有一个问题Android原生的补间动画只是视觉上的UI变化对象属性并非真正改变那么Flutter是否也是如此 答案非也是真的改变了和Android原生补间动画不同看图 以下偏移动画在Flutter中的点击偏移后的矩形位置可以触发提示反之Android原生不可以只能在矩形原来的位置才能触发 Flutte 提示库 以及 封装相关 的代码 fluttertoast: ^8.2.4 toast_util.dart import package:flutter/material.dart; import package:fluttertoast/fluttertoast.dart;class ToastUtil {static FToast fToast FToast();static void init(BuildContext context) {fToast.init(context);}static void showToast(String msg) {Widget toast Row(mainAxisAlignment: MainAxisAlignment.center,children: [Container(padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),decoration: BoxDecoration(borderRadius: BorderRadius.circular(25.0),color: Colors.greenAccent,),alignment: Alignment.center,child: Text(msg),)],);fToast.showToast(child: toast,gravity: ToastGravity.BOTTOM,toastDuration: const Duration(seconds: 2),);} }Flutter显示动画 代码 import package:flutter/material.dart; import package:flutter_animation/util/toast_util.dart;class TweenAnimation extends StatefulWidget {const TweenAnimation({super.key});overrideStateTweenAnimation createState() _TweenAnimationState(); }/// 测试显式动画属性是否真的改变了 class _TweenAnimationState extends StateTweenAnimationwith SingleTickerProviderStateMixin {late AnimationOffset animation;late AnimationController controller;overridevoid initState() {super.initState();controller AnimationController(duration: const Duration(milliseconds: 500), vsync: this);animation TweenOffset(begin: const Offset(0, 0), end: const Offset(1.5, 0)).animate(controller)..addStatusListener((status) {debugPrint(status$status); // 监听动画执行状态});}overridevoid dispose() {controller.dispose();super.dispose();}overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Flutter 显式动画,style: TextStyle(fontSize: 20),)),body: Container(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,color: Colors.primaries[5],child: Stack(children: [Align(alignment: Alignment.center,child: Container(width: 80,height: 80,decoration: BoxDecoration(border: Border.all(color: Colors.white, width: 1.0),),),),Align(alignment: Alignment.center,child: SlideTransition(position: animation,child: InkWell(onTap: () {ToastUtil.showToast(点击了);},child: Container(width: 80,height: 80,color: Colors.primaries[2],),),),),Positioned(left: (MediaQuery.of(context).size.width / 2) - 35,top: 200,child: ElevatedButton(onPressed: () {if (controller.isCompleted) {controller.reverse();} else {controller.forward();}// controller.forward(); // 向前执行 begin 到 end 的动画执行结束后处于end状态// controller.reverse(); // 反向当动画已经完成进行还原动画// controller.reset(); // 重置当动画已经完成进行还原注意这个是直接还原没有动画},child: const Text(偏移),),)],),),);} } Flutter隐式动画 代码 import package:flutter/material.dart; import package:flutter_animation/util/toast_util.dart;class ImplicitAnimation extends StatefulWidget {const ImplicitAnimation({super.key});overrideStateImplicitAnimation createState() _ImplicitAnimationState(); }/// 测试隐式动画属性是否真的改变了 class _ImplicitAnimationState extends StateImplicitAnimation {late double offsetX 0;overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Flutter 隐式动画,style: TextStyle(fontSize: 20),)),body: Container(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,color: Colors.primaries[5],child: Stack(children: [Align(alignment: Alignment.center,child: Container(width: 80,height: 80,decoration: BoxDecoration(border: Border.all(color: Colors.white, width: 1.0),),),),Align(alignment: Alignment.center,child: AnimatedSlide(offset: Offset(offsetX, 0),duration: const Duration(milliseconds: 500),child: InkWell(onTap: () {ToastUtil.showToast(点击了);},child: Container(width: 80,height: 80,color: Colors.primaries[2],),),),),Positioned(left: (MediaQuery.of(context).size.width / 2) - 35,top: 200,child: ElevatedButton(onPressed: () {if (offsetX 0) {offsetX 1.5;} else {offsetX 0;}setState(() {});},child: const Text(偏移),),)],),),);} } Android原生补间动画 代码 ?xml version1.0 encodingutf-8? FrameLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticalTextViewandroid:layout_widthmatch_parentandroid:layout_height50dpandroid:backgroundandroid:color/holo_blue_lightandroid:gravitycenter|leftandroid:textAndroid原生 补间动画android:paddingStart16dpandroid:textColorandroid:color/whiteandroid:textSize20sp /TextViewandroid:idid/borderandroid:layout_width50dpandroid:layout_height50dpandroid:layout_gravitycenterandroid:layout_marginBottom50dpandroid:backgrounddrawable/border /TextViewandroid:idid/offset_boxandroid:layout_width50dpandroid:layout_height50dpandroid:layout_gravitycenterandroid:layout_marginBottom50dpandroid:backgroundandroid:color/holo_orange_light /Buttonandroid:idid/offset_xandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenterandroid:layout_marginTop12dpandroid:text偏移 //FrameLayout import android.app.Activity import android.os.Bundle import android.view.View import android.view.animation.TranslateAnimation import android.widget.Toast import com.example.flutter_animation.databinding.ActivityMainBindingclass MainActivity : Activity(), View.OnClickListener {private lateinit var bind: ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)bind ActivityMainBinding.inflate(layoutInflater)setContentView(bind.root)bind.offsetX.setOnClickListener(this)bind.offsetBox.setOnClickListener(this)}private fun offsetAnimation() {val translateAnimation TranslateAnimation(0f, 200f, 0f, 0f)translateAnimation.duration 800translateAnimation.fillAfter truebind.offsetBox.startAnimation(translateAnimation)}override fun onClick(v: View?) {if (bind.offsetX v) {offsetAnimation()} else if (bind.offsetBox v) {Toast.makeText(this,点击了,Toast.LENGTH_SHORT).show()}}} Hero动画 应用于 元素共享 的动画。 下面这三个图片详情案例的使用方式将 Widget 从 A页面 共享到 B页面 后改变Widget大小被称为 标准 hero 动画 图片详情案例一本地图片 import package:flutter/cupertino.dart; import package:flutter/material.dart;import package:flutter/scheduler.dart show timeDilation;class HeroAnimation extends StatefulWidget {const HeroAnimation({super.key});overrideStateHeroAnimation createState() _HeroAnimationState(); }/// 将 Widget 从 A页面 共享到 B页面 后改变Widget大小 class _HeroAnimationState extends StateHeroAnimation {/// 测试本地图片final ListString images [assets/images/01.jpg,assets/images/02.jpg,assets/images/03.jpg,assets/images/04.jpg,];overrideWidget build(BuildContext context) {// 减慢动画速度可以通过此值帮助开发,// 注意这个值是针对所有动画所以路由动画也会受影响// timeDilation 10.0;return Scaffold(appBar: AppBar(title: const Text(Photo List Page),),body: Container(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,alignment: Alignment.topLeft,child: GridView.count(padding: const EdgeInsets.all(10),crossAxisCount: 2,mainAxisSpacing: 10,crossAxisSpacing: 10,children: List.generate(images.length,(index) PhotoHero(photo: images[index],size: 100,onTap: () {Navigator.of(context).push(CupertinoPageRoutevoid(builder: (context) PhotoDetail(size: MediaQuery.of(context).size.width,photo: images[index]),));},)),),),);} }class PhotoHero extends StatelessWidget {const PhotoHero({super.key,required this.photo,this.onTap,required this.size,});final String photo;final VoidCallback? onTap;final double size;overrideWidget build(BuildContext context) {return SizedBox(width: size,height: size,child: Hero(tag: photo,child: Material(color: Colors.transparent,child: InkWell(onTap: onTap,/// 测试本地图片child: Image.asset(photo,fit: BoxFit.cover,),),),),);} }class PhotoDetail extends StatelessWidget {const PhotoDetail({super.key,required this.photo,required this.size,});final String photo;final double size;overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Photo Detail Page),),body: Column(children: [Container(color: Colors.lightBlueAccent,padding: const EdgeInsets.all(16),alignment: Alignment.topCenter,child: PhotoHero(photo: photo,size: size,onTap: () {Navigator.of(context).pop();},),),const Text(详情xxx,style: TextStyle(fontSize: 20),)],),);} }图片详情案例二网络图片 可以看出在有延迟的情况下效果没有本地图片好 import package:flutter/cupertino.dart; import package:flutter/material.dart;import package:flutter/scheduler.dart show timeDilation;class HeroAnimation extends StatefulWidget {const HeroAnimation({super.key});overrideStateHeroAnimation createState() _HeroAnimationState(); }/// 将 Widget 从 A页面 共享到 B页面 后改变Widget大小 class _HeroAnimationState extends StateHeroAnimation {/// 测试网络图片final ListString images [https://img1.baidu.com/it/u1161835547,3275770506fm253fmtautoapp138fJPEG?w800h500,https://p9.toutiaoimg.com/origin/pgc-image/6d817289d3b44d53bb6e55aa81e41bd2?frompc,https://img0.baidu.com/it/u102503057,4196586556fm253fmtautoapp138fBMP?w500h724,https://lmg.jj20.com/up/allimg/1114/041421115008/210414115008-3-1200.jpg,];overrideWidget build(BuildContext context) {// 减慢动画速度可以通过此值帮助开发,// 注意这个值是针对所有动画所以路由动画也会受影响// timeDilation 10.0;return Scaffold(appBar: AppBar(title: const Text(Photo List Page),),body: Container(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,alignment: Alignment.topLeft,child: GridView.count(padding: const EdgeInsets.all(10),crossAxisCount: 2,mainAxisSpacing: 10,crossAxisSpacing: 10,children: List.generate(images.length,(index) PhotoHero(photo: images[index],size: 100,onTap: () {Navigator.of(context).push(CupertinoPageRoutevoid(builder: (context) PhotoDetail(size: MediaQuery.of(context).size.width,photo: images[index]),));},)),),),);} }class PhotoHero extends StatelessWidget {const PhotoHero({super.key,required this.photo,this.onTap,required this.size,});final String photo;final VoidCallback? onTap;final double size;overrideWidget build(BuildContext context) {return SizedBox(width: size,height: size,child: Hero(tag: photo,child: Material(color: Colors.transparent,child: InkWell(onTap: onTap,/// 测试网络图片child: Image.network(photo,fit: BoxFit.cover,),),),),);} }class PhotoDetail extends StatelessWidget {const PhotoDetail({super.key,required this.photo,required this.size,});final String photo;final double size;overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Photo Detail Page),),body: Column(children: [Container(color: Colors.lightBlueAccent,padding: const EdgeInsets.all(16),alignment: Alignment.topCenter,child: PhotoHero(photo: photo,size: size,onTap: () {Navigator.of(context).pop();},),),const Text(详情xxx,style: TextStyle(fontSize: 20),)],),);} }图片详情案例三背景透明 import package:flutter/material.dart;import package:flutter/scheduler.dart show timeDilation;class HeroAnimation extends StatefulWidget {const HeroAnimation({super.key});overrideStateHeroAnimation createState() _HeroAnimationState(); }/// 测试 新页面背景透明色 的图片详情 class _HeroAnimationState extends StateHeroAnimation {/// 测试本地图片final ListString images [assets/images/01.jpg,assets/images/02.jpg,assets/images/03.jpg,assets/images/04.jpg,];overrideWidget build(BuildContext context) {// 减慢动画速度可以通过此值帮助开发,// 注意这个值是针对所有动画所以路由动画也会受影响// timeDilation 10.0;return Scaffold(appBar: AppBar(title: const Text(Photo List Page),),body: Container(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,alignment: Alignment.topLeft,child: GridView.count(padding: const EdgeInsets.all(10),crossAxisCount: 2,mainAxisSpacing: 10,crossAxisSpacing: 10,children: List.generate(images.length,(index) PhotoHero(photo: images[index],size: 100,onTap: () {Navigator.of(context).push(PageRouteBuildervoid(opaque: false, // 新页面背景色不透明度pageBuilder: (context, animation, secondaryAnimation) {return PhotoDetail(size: MediaQuery.of(context).size.width,photo: images[index]);},),);},)),),),);} }class PhotoHero extends StatelessWidget {const PhotoHero({super.key,required this.photo,this.onTap,required this.size,});final String photo;final VoidCallback? onTap;final double size;overrideWidget build(BuildContext context) {return SizedBox(width: size,height: size,child: Hero(tag: photo,child: Material(color: Colors.transparent,child: InkWell(onTap: onTap,/// 测试本地图片child: Image.asset(photo,fit: BoxFit.cover,),),),),);} }class PhotoDetail extends StatelessWidget {const PhotoDetail({super.key,required this.photo,required this.size,});final String photo;final double size;overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.transparent,// backgroundColor: const Color(0x66000000),body: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Container(padding: const EdgeInsets.all(16),alignment: Alignment.center,child: PhotoHero(photo: photo,size: size,onTap: () {Navigator.of(context).pop();},),),const Text(详情xxx,style: TextStyle(fontSize: 20,color: Colors.white),)],),);} } 图片形状转换案例圆形 转 矩形 这个案例的使用方式被称为 径向hero动画 径向hero动画的 径 是半径距离圆形状 向 矩形状转换矩形状的对角半径距离 圆形状半径距离 * 2这个是官方模版代码我也没改什么;官方代码地址https://github.com/cfug/flutter.cn/blob/main/examples/_animation/radial_hero_animation/lib/main.dart问题这种官方代码是 初始化为 圆形 点击向 矩形改变的方式我尝试反向操作初始化为 矩形 点击向 圆形改变但没有成功如果有哪位同学找到实现方式麻烦评论区留言 我是这样修改的 class RadialExpansion extends StatelessWidget {... ... overrideWidget build(BuildContext context) {/// 原来的代码// 控制形状变化的核心代码// return ClipOval( // 圆形// child: Center(// child: SizedBox(// width: clipRectSize,// height: clipRectSize,// child: ClipRect( // 矩形// child: child,// ),// ),// ),// );/// 尝试修改 形状顺序return ClipRect( // 矩形child: Center(child: SizedBox(width: clipRectSize,height: clipRectSize,child: ClipOval( // 圆形child: child,),),),);} } 官方代码演示  import package:flutter/material.dart; import dart:math as math;import package:flutter/scheduler.dart show timeDilation;class HeroAnimation extends StatefulWidget {const HeroAnimation({super.key});overrideStateHeroAnimation createState() _HeroAnimationState(); }/// 将 Widget 从 A页面 共享到 B页面 后改变Widget形状 class _HeroAnimationState extends StateHeroAnimation {static double kMinRadius 32.0;static double kMaxRadius 128.0;static Interval opacityCurve const Interval(0.0, 0.75, curve: Curves.fastOutSlowIn);static RectTween _createRectTween(Rect? begin, Rect? end) {return MaterialRectCenterArcTween(begin: begin, end: end);}static Widget _buildPage(BuildContext context, String imageName, String description) {return Container(color: Theme.of(context).canvasColor,child: Center(child: Card(elevation: 8,child: Column(mainAxisSize: MainAxisSize.min,children: [SizedBox(width: kMaxRadius * 2.0,height: kMaxRadius * 2.0,child: Hero(createRectTween: _createRectTween,tag: imageName,child: RadialExpansion(maxRadius: kMaxRadius,child: Photo(photo: imageName,onTap: () {Navigator.of(context).pop();},),),),),Text(description,style: const TextStyle(fontWeight: FontWeight.bold),textScaleFactor: 3,),const SizedBox(height: 16),],),),),);}Widget _buildHero(BuildContext context,String imageName,String description,) {return SizedBox(width: kMinRadius * 2.0,height: kMinRadius * 2.0,child: Hero(createRectTween: _createRectTween,tag: imageName,child: RadialExpansion(maxRadius: kMaxRadius,child: Photo(photo: imageName,onTap: () {Navigator.of(context).push(PageRouteBuildervoid(pageBuilder: (context, animation, secondaryAnimation) {return AnimatedBuilder(animation: animation,builder: (context, child) {return Opacity(opacity: opacityCurve.transform(animation.value),child: _buildPage(context, imageName, description),);},);},),);},),),),);}overrideWidget build(BuildContext context) {timeDilation 5.0; // 1.0 is normal animation speed.return Scaffold(appBar: AppBar(title: const Text(Radial Transition Demo),),body: Container(padding: const EdgeInsets.all(32),alignment: FractionalOffset.bottomLeft,child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [_buildHero(context, assets/images/01.jpg, Chair),_buildHero(context, assets/images/02.jpg, Binoculars),_buildHero(context, assets/images/03.jpg, Beach ball),_buildHero(context, assets/images/04.jpg, Beach ball),],),),);} }class Photo extends StatelessWidget {const Photo({super.key, required this.photo, this.onTap});final String photo;final VoidCallback? onTap;overrideWidget build(BuildContext context) {return Material(// Slightly opaque color appears where the image has transparency.color: Theme.of(context).primaryColor.withOpacity(0.25),child: InkWell(onTap: onTap,child: LayoutBuilder(builder: (context, size) {return Image.asset(photo,fit: BoxFit.contain,);},),),);} }class RadialExpansion extends StatelessWidget {const RadialExpansion({super.key,required this.maxRadius,this.child,}) : clipRectSize 2.0 * (maxRadius / math.sqrt2);final double maxRadius;final double clipRectSize;final Widget? child;overrideWidget build(BuildContext context) {// 控制形状变化的核心代码return ClipOval( // 圆形child: Center(child: SizedBox(width: clipRectSize,height: clipRectSize,child: ClipRect( // 矩形child: child,),),),);} } 页面转场动画 在自定义路由时添加动画自定义路由需要用到PageRouteBuilderT import package:flutter/material.dart;/// 为页面切换加入动画效果 class PageAnimation extends StatefulWidget {const PageAnimation({super.key});overrideStatePageAnimation createState() _PageAnimationState(); }class _PageAnimationState extends StatePageAnimation {overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(为页面切换加入动画效果,style: TextStyle(fontSize: 20),)),body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [ElevatedButton(onPressed: () {Navigator.of(context).push(_createRouteX());},child: const Text(X轴偏移,style: TextStyle(fontSize: 20),)),ElevatedButton(onPressed: () {Navigator.of(context).push(_createRouteY());},child: const Text(Y轴偏移,style: TextStyle(fontSize: 20),)),ElevatedButton(onPressed: () {Navigator.of(context).push(_createRouteMix());},child: const Text(混合动画,style: TextStyle(fontSize: 20),)),],),),);}/// X轴 平移动画切换页面Route _createRouteX() {return PageRouteBuilder(// opaque: false, // 新页面背景色不透明度pageBuilder: (context, animation, secondaryAnimation) const TestPage01(),transitionsBuilder: (context, animation, secondaryAnimation, child) {const begin Offset(1.0, 0.0); // 将 dx 参数设为 1这代表在水平方向左切换整个页面的宽度const end Offset.zero;const curve Curves.ease;var tween Tween(begin: begin, end: end).chain(CurveTween(curve: curve));return SlideTransition(position: animation.drive(tween),child: child,);});}/// Y轴 平移动画切换页面Route _createRouteY() {return PageRouteBuilder(// opaque: false, // 新页面背景色不透明度pageBuilder: (context, animation, secondaryAnimation) const TestPage01(),transitionsBuilder: (context, animation, secondaryAnimation, child) {const begin Offset(0.0, 1.0); // 将 dy 参数设为 1这代表在竖直方向上切换整个页面的高度const end Offset.zero;const curve Curves.ease;var tween Tween(begin: begin, end: end).chain(CurveTween(curve: curve));return SlideTransition(position: animation.drive(tween),child: child,);});}/// 多个动画配合切换页面Route _createRouteMix() {return PageRouteBuilder(// opaque: false, // 新页面背景色不透明度pageBuilder: (context, animation, secondaryAnimation) const TestPage01(),transitionsBuilder: (context, animation, secondaryAnimation, child) {var tween Tweendouble(begin: 0.1, end: 1.0).chain(CurveTween(curve: Curves.ease));return FadeTransition(// 淡入淡出opacity: animation.drive(tween),child: RotationTransition(// 旋转turns: animation.drive(tween),child: ScaleTransition(// 更替scale: animation.drive(tween),child: child,),),);});} }class TestPage01 extends StatelessWidget {const TestPage01({super.key});overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.lightBlue,appBar: AppBar(title: const Text(TestPage01),),);} }交错动画 多个动画配合使用 这个案例是官方的原汁原味 import package:flutter/material.dart; import package:flutter/scheduler.dart show timeDilation;class IntertwinedAnimation extends StatefulWidget {const IntertwinedAnimation({super.key});overrideStateIntertwinedAnimation createState() _IntertwinedAnimationState(); }class _IntertwinedAnimationState extends StateIntertwinedAnimationwith SingleTickerProviderStateMixin {late AnimationController _controller;overridevoid initState() {super.initState();_controller AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);}overridevoid dispose() {_controller.dispose();super.dispose();}Futurevoid _playAnimation() async {try {await _controller.forward().orCancel;await _controller.reverse().orCancel;} on TickerCanceled {}}overrideWidget build(BuildContext context) {// timeDilation 10.0;return Scaffold(appBar: AppBar(title: const Text(交错动画,style: TextStyle(fontSize: 20),)),body: GestureDetector(behavior: HitTestBehavior.opaque,onTap: () {_playAnimation();},child: Center(child: Container(width: 300,height: 300,decoration: BoxDecoration(color: Colors.black.withOpacity(0.1),border: Border.all(color: Colors.black.withOpacity(0.5),)),child: StaggerAnimation(controller: _controller),),),),);} }class StaggerAnimation extends StatelessWidget {final Animationdouble controller;final Animationdouble opacity;final Animationdouble width;final Animationdouble height;final AnimationEdgeInsets padding;final AnimationBorderRadius? borderRadius;final AnimationColor? color;StaggerAnimation({super.key, required this.controller}): opacity Tweendouble(begin: 0.0,end: 1.0,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.0,0.100,curve: Curves.ease,))),width Tweendouble(begin: 50.0,end: 150.0,).animate(CurvedAnimation(parent: controller,curve: const Interval(0.125,0.250,curve: Curves.ease,))),height Tweendouble(begin: 50.0, end: 150.0).animate(CurvedAnimation(parent: controller,curve: const Interval(0.250,0.375,curve: Curves.ease,))),padding EdgeInsetsTween(begin: const EdgeInsets.only(bottom: 16),end: const EdgeInsets.only(bottom: 75),).animate(CurvedAnimation(parent: controller,curve: const Interval(0.250,0.375,curve: Curves.ease,))),borderRadius BorderRadiusTween(begin: BorderRadius.circular(4),end: BorderRadius.circular(75),).animate(CurvedAnimation(parent: controller,curve: const Interval(0.375,0.500,curve: Curves.ease,))),color ColorTween(begin: Colors.indigo[100], end: Colors.orange[400]).animate(CurvedAnimation(parent: controller,curve: const Interval(0.500,0.750,curve: Curves.ease,)));Widget _buildAnimation(BuildContext context, Widget? child) {return Container(padding: padding.value,alignment: Alignment.bottomCenter,child: Opacity(opacity: opacity.value,child: Container(width: width.value,height: height.value,decoration: BoxDecoration(color: color.value,border: Border.all(color: Colors.indigo[300]!,width: 3,),borderRadius: borderRadius.value),),),);}overrideWidget build(BuildContext context) {return AnimatedBuilder(builder: _buildAnimation,animation: controller,);} } 依次执行动画 这个案例是根据官方demo改的它那个太复杂了不利于新手阅读个人觉得 官方文档创建一个交错效果的侧边栏菜单 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter import package:flutter/material.dart;class Intertwined02Animation extends StatefulWidget {const Intertwined02Animation({super.key});overrideStateIntertwined02Animation createState() _Intertwined02AnimationState(); }class _Intertwined02AnimationState extends StateIntertwined02Animation {overrideWidget build(BuildContext context) {return Scaffold(body: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: const TableList(),// child: const Column(// crossAxisAlignment: CrossAxisAlignment.center,// children: [// TableList()// ],// ),),);} }class TableList extends StatefulWidget {const TableList({super.key});overrideStateTableList createState() _TableListState(); }class _TableListState extends StateTableList with SingleTickerProviderStateMixin {/// 遍历循环写法late AnimationController _controller;final Duration _durationTime const Duration(milliseconds: 3000);overrideinitState() {super.initState();_controller AnimationController(vsync: this, duration: _durationTime);_controller.forward();}overridevoid dispose() {_controller.dispose();super.dispose();}/// 遍历IntervalListInterval _createInterval() {ListInterval intervals [];// Interval(0.0,0.5);// Interval(0.5,0.75);// Interval(0.75,1.0);double begin 0.0;double end 0.5;for (int i 0; i 3; i) {if (i 0) {intervals.add(Interval(begin, end));} else {begin end;end begin 0.25;intervals.add(Interval(begin, end));}// debugPrint(begin$begin --- end$end);}return intervals;}/// 遍历循环组件ListWidget _createWidget() {var intervals _createInterval();ListWidget listItems [];for (int i 0; i 3; i) {listItems.add(AnimatedBuilder(animation: _controller,builder: (context, child) {var animationPercent Curves.easeOut.transform(intervals[i].transform(_controller.value));final opacity animationPercent;final slideDistance (1.0 - animationPercent) * 150;return Opacity(opacity: i 2 ? opacity : 1,child: Transform.translate(offset: Offset(slideDistance, 100 (i * 50)),child: child,));},child: Container(width: 100,height: 50,color: Colors.lightBlue,),));}return listItems;}overrideWidget build(BuildContext context) {return SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Column(children: _createWidget(),),);}/// 非遍历循环写法 // late AnimationController _controller; // // final Interval _intervalA const Interval(0.0, 0.5); // final Interval _intervalB const Interval(0.5, 0.8); // final Interval _intervalC const Interval(0.8, 1.0); // // final Duration _durationTime const Duration(milliseconds: 3000); // // override // void initState() { // super.initState(); // _controller AnimationController(vsync: this, duration: _durationTime); // _controller.forward(); // } // // override // void dispose() { // _controller.dispose(); // super.dispose(); // } // // override // Widget build(BuildContext context) { // return SizedBox( // width: MediaQuery.of(context).size.width, // height: MediaQuery.of(context).size.height, // child: Column( // children: [ // AnimatedBuilder( // animation: _controller, // builder: (context,child) { // var animationPercent Curves.easeOut.transform(_intervalA.transform(_controller.value)); // final slideDistance (1.0 - animationPercent) * 150; // return Transform.translate( // offset: Offset(slideDistance,100), // child: child // ); // }, // child: Container( // width: 100, // height: 50, // color: Colors.lightBlue, // ), // ), // AnimatedBuilder( // animation: _controller, // builder: (context,child) { // var animationPercent Curves.easeOut.transform(_intervalB.transform(_controller.value)); // final slideDistance (1.0 - animationPercent) * 150; // return Transform.translate( // offset: Offset(slideDistance,150), // child: child // ); // }, // child: Container( // width: 100, // height: 50, // color: Colors.lightBlue, // ), // ), // AnimatedBuilder( // animation: _controller, // builder: (context,child) { // var animationPercent Curves.easeOut.transform(_intervalC.transform(_controller.value)); // final opacity animationPercent; // final slideDistance (1.0 - animationPercent) * 150; // return Opacity( // opacity: opacity, // child: Transform.translate( // offset: Offset(slideDistance,200), // child: child // ), // ); // }, // child: Container( // width: 100, // height: 50, // color: Colors.lightBlue, // ), // ), // ], // ), // ); // }/// 基础版本写法 // late AnimationController _controller; // final Duration _durationTime const Duration(milliseconds: 2000); // // 0.0 - 1.0 / 0% - 100% // final Interval _interval const Interval(0.5, 1.0); // 延迟 50% 再开始 启动动画执行到 100% // // final Interval _interval const Interval(0.5, 0.7); // 延迟 50% 再开始 启动动画后期的执行速度增加 30% // // final Interval _interval const Interval(0.0, 0.1); // 不延迟 动画执行速度增加 90% // // override // void initState() { // super.initState(); // _controller AnimationController(vsync: this, duration: _durationTime); // _controller.forward(); // } // // override // void dispose() { // _controller.dispose(); // super.dispose(); // }// override // Widget build(BuildContext context) { // return AnimatedBuilder( // animation: _controller, // builder: (context,child) { // // var animationPercent Curves.easeOut.transform(_controller.value); // 加动画曲线 // // var animationPercent _interval.transform(_controller.value); // 加动画间隔 // var animationPercent Curves.easeOut.transform(_interval.transform(_controller.value)); // 动画曲线 动画间隔 // // final slideDistance (1.0 - animationPercent) * 150; // 就是对150 做递减 // // debugPrint(animationPercent$animationPercent --- slideDistance$slideDistance); // debugPrint(slideDistance$slideDistance); // // return Transform.translate( // offset: Offset(0,slideDistance), // child: child // ); // }, // child: Container( // width: 100, // height: 50, // color: Colors.lightBlue, // ), // ); // } }官方文档 动画效果介绍 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
http://www.dnsts.com.cn/news/176944.html

相关文章:

  • 网站开发综合设计报告涿州网站建设有限公司
  • 网站建设模板价格网站被k什么意思
  • 泉州网站建设哪家专业wordpress中页面伪静态页面
  • 贵州网站设计公司seo策略分析
  • 免费网页上传网站软件公司运营是做什么的
  • 学做美食视频网站有哪些购物网站怎么做优化
  • 家教网站开发公司游戏网站设计
  • 微网站建设及微信推广方案ppt模板深圳中装建设集团网站
  • 论坛网站推广wordpress主题安装在哪个文件夹
  • 万户网站建设公司网页设计存在的问题及分析
  • 建设电子商务网站的启示如何成立网站
  • 未来的网站建设想法菏泽网站开发
  • 网站开发设计南邮广东建设厅官网证件查询
  • 阿里巴巴网站威海哪里做?上海网站开发
  • 网站备案注销原因小程序营销策划方案
  • 淘宝活动策划网站网站接入支付宝在线交易怎么做
  • 辽宁网站推广的目的嘉兴建设网站的
  • 建网站工具想做外贸怎么找客户
  • 雅安工程交易建设网站个人 做自媒体 建网站
  • 网站开发培训中心企业名称注册查询官网入口
  • 北京交易网站建设表白网页生成器下载
  • 个人域名做企业网站全国设计师网站
  • 廊坊网站建设-商昊网络上海公司网站
  • asp网站例子怎么做代理网站
  • 10有免费建网站电子商务营销案例
  • wordpress制作网站福建建设工程信息网官网
  • 如何选择坪山网站建设太原网站推广怎么做
  • 网站建设小工具企业网络营销策划方案视频
  • 有没有做装修中介的网站网站建设记录过程
  • 个人网站建设制作苏州制作网页找哪家