程序员开发实例大全宝库

网站首页 > 编程文章 正文

一个漂亮的Flutter动画学习项目(flutter listview 动画)

zazugpt 2024-08-25 17:26:31 编程文章 16 ℃ 0 评论

首页感谢大家的支持,发出去的文章被点赞、转发、收藏,说明对大家有用,这样的写作我会坚持下去,坚持分享Flutter项目给大家。

朋友养的鱼死了,悲伤不已。


他不想给鱼土葬,说想给它火葬,然后再把鱼

的骨灰撤回大海,好让它再回到母亲的怀抱。

谁知道那玩意儿越烤越香,后来就买了两瓶啤

酒......


很多事情,人们走着走着,就忘了初心。


——生活就是这样,变化太快,我们连自己的心情都无法控制。

本头条核心宗旨

欢迎来到「技术刚刚好」作者,「技术刚刚好」是个人维护,每天至少更新一篇Flutter技术文章,实时为大家播报Flutter最新消息。如果你刚好也在关注Flutter这门技术,那就跟我一起学习进步吧,你的赞,收藏,转发是对我个人最大的支持,维护不易,欢迎关注。

技术刚刚好经历

近几年,移动端跨平台开发技术层出不穷,从Facebook家的ReactNative,到阿里家WEEX,前端技术在移动端跨平台开发中大展身手,技术刚刚好作为一名Android开发,经历了从Reactjs到Vuejs的不断学习。而在2018年,我们的主角变成了Flutter,这是Goolge开源的一个移动端跨平台解决方案,可以快速开发精美的移动App。希望跟大家一起学习,一起进步!

本文核心要点

今天分享一个漂亮的登录页面,打开会有一个正在加载中动画,成功后就进入登录页面,一个动态加载文字动画,图片也跟着移动起来。


pubspec.yaml文件

这个文件都很正常,就是一个图片加载配置。

main.dart文件

import 'package:flutter/material.dart';

import 'package:travel/splash_page.dart';
import 'package:travel/landing_page.dart';

class TravelApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return new MaterialApp(
 title: "Travel App",
 onGenerateRoute: (RouteSettings settings) {
 switch (settings.name) {
 case '/landing':
 return new SplashPageToLandingPageRoute(
 builder: (_) => new LandingPage(),
 settings: settings
 );
 }
 },
 home: new SplashPage(),
 );
 }
}

void main() => runApp(new TravelApp());

class SplashPageToLandingPageRoute<T> extends MaterialPageRoute<T> {
 SplashPageToLandingPageRoute(
 { WidgetBuilder builder, RouteSettings settings })
 : super(builder: builder, settings: settings);

 @override
 Duration get transitionDuration => new Duration(milliseconds: 1500);

 @override
 Widget buildTransitions(BuildContext context,
 Animation<double> animation,
 Animation<double> secondaryAnimation,
 Widget child) {
 if (settings.isInitialRoute)
 return child;

 final curve = new CurvedAnimation(
 parent: animation, curve: Curves.easeInOut);
 return new FadeTransition(opacity: curve, child: child);
 }
}

LandingPage文件

import 'package:flutter/material.dart';
import 'package:travel/animated_background.dart';
import 'package:travel/animated_locations_text.dart';
import 'package:travel/animated_text.dart';
import 'package:travel/spread_circles.dart';
import 'package:travel/stacked_circles.dart';


class LandingPage extends StatefulWidget {

 @override
 State createState() => new LandingPageState();
}

class LandingPageState extends State<LandingPage>
 with TickerProviderStateMixin {

 AnimationController buttonAnimationController;
 Animation<AlignmentGeometry> buttonAlignment;
 Animation<double> buttonOpacity;

 @override
 void initState() {
 super.initState();
 buttonAnimationController = new AnimationController(
 vsync: this, duration: new Duration(milliseconds: 1000));

 buttonAlignment = new AlignmentTween(
 begin: new Alignment(0.0, 1.0),
 end: new Alignment(0.0, 0.95),
 ).animate(new CurvedAnimation(
 parent: buttonAnimationController,
 curve: new Interval(0.3, 0.9, curve: Curves.easeInOut),));
 buttonOpacity = new Tween<double>(
 begin: 0.0,
 end: 1.0,
 ).animate(new CurvedAnimation(
 parent: buttonAnimationController,
 curve: new Interval(0.3, 1.0, curve: Curves.easeInOut),));

 buttonAlignment.addListener(() {
 setState(() {});
 });
 buttonOpacity.addListener(() {
 setState(() {});
 });

 buttonAnimationController.forward();
 }

 @override
 void dispose() {
 buttonAnimationController.dispose();
 }

 @override
 Widget build(BuildContext context) {
 return new Scaffold(
 body: new Stack(
 children: <Widget>[
 new AnimatedBackground(),
 _buildStackedCircles(),
 new SpreadCircles(),
 _buildButtomButtons(),
 _buildAnimatedText(),
 ],
 ),
 );
 }

 Widget _buildAnimatedText() {
 final animatedTextDelay = 800;

 return new Align(
 alignment: new Alignment(-1.0, -0.75),
 child: new Padding(
 padding: const EdgeInsets.only(left: 15.0),
 child: new Column(
 mainAxisSize: MainAxisSize.min,
 mainAxisAlignment: MainAxisAlignment.start,
 crossAxisAlignment: CrossAxisAlignment.start,
 children: <Widget>[
 new AnimatedText(
 "Find your perfect \nholiday home in", animatedTextDelay,
 durationInMilliseconds: 2500),
 new AnimatedLocationsText(animatedTextDelay + 2500),
 ],
 ),
 )
 );
 }

 Widget _buildStackedCircles() {
 final circleDiameter = 25.0;
 return new Align(
 alignment: new Alignment(0.0, -0.9),
 child: new Hero(
 tag: "CircleHeroTag",
 child: new StackedCircles(circleDiameter),
 ),
 );
 }

 Widget _buildButtomButtons() {
 return new AnimatedBuilder(
 animation: buttonAnimationController,
 child: new Container(
 padding: const EdgeInsets.only(left: 15.0, right: 15.0),
 child: new Column(
 mainAxisSize: MainAxisSize.min,
 children: <Widget>[
 _createAccountButton(),
 new Padding(padding: const EdgeInsets.only(bottom: 10.0)),
 _signInButton(),
 new Padding(padding: const EdgeInsets.only(bottom: 10.0)),
 _termsAndConditions(),
 ],
 ),
 ),
 builder: (BuildContext context, Widget child) {
 return new Align(
 alignment: buttonAlignment.value,
 child: new Opacity(
 opacity: buttonOpacity.value,
 child: child,
 ),
 );
 }
 );
 }

 Widget _createAccountButton() {
 return new GestureDetector(
 child: new Material(
 child: new Container(
 padding: const EdgeInsets.only(top: 10.0, bottom: 10.0),
 decoration: new BoxDecoration(
 borderRadius: new BorderRadius.circular(5.0),
 gradient: new LinearGradient(
 colors: <Color>[
 Colors.green,
 Colors.greenAccent,
 ]
 ),
 ),
 alignment: Alignment.center,
 child: new Text("Create account",
 style: new TextStyle(color: Colors.white,
 fontSize: 16.0,
 fontWeight: FontWeight.w500),),
 ),
 ),
 onTap: () {},
 );
 }

 Widget _signInButton() {
 return new GestureDetector(
 child: new Material(
 child: new Container(
 padding: const EdgeInsets.only(top: 10.0, bottom: 10.0),
 decoration: new BoxDecoration(
 borderRadius: new BorderRadius.circular(5.0),
 gradient: new LinearGradient(
 colors: <Color>[
 Colors.grey.withAlpha(150),
 Colors.grey.withAlpha(100),
 ]
 ),
 ),
 alignment: Alignment.center,
 child: new Text("Sign in",
 style: new TextStyle(color: Colors.black54,
 fontSize: 16.0,
 fontWeight: FontWeight.w500),),
 ),
 ),
 onTap: () {},
 );
 }

 Widget _termsAndConditions() {
 final textStyle = new TextStyle(fontSize: 13.0, color: Colors.black38);
 return new RichText(
 textAlign: TextAlign.center,
 text: new TextSpan(
 text: "By signing up to our services you indicate that you have read and agree to our ",
 style: textStyle,
 children: <TextSpan>[
 new TextSpan(text: "terms and conditions",
 style: new TextStyle(decoration: TextDecoration.underline)),
 ],
 ),
 );
 }
}

Circle文件

import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

class Circle extends StatelessWidget {

 final Color color;
 final double diameter;
 final Offset center;

 Circle({@required this.color, @required this.diameter, this.center});

 @override
 Widget build(BuildContext context) {
 return new CustomPaint(
 size: new Size(diameter, diameter),
 painter: new CirclePainter(color, center: center),
 );
 }

}

class CirclePainter extends CustomPainter {

 final Color color;
 final Offset center;

 CirclePainter(this.color, {this.center});

 @override
 void paint(Canvas canvas, Size size) {
 canvas.drawCircle(
 center ?? new Offset(size.width / 2, size.height / 2), size.width / 2,
 new Paint()..color = this.color);
 }

 @override
 bool shouldRepaint(CirclePainter oldDelegate) => true;

}

AnimatedText文件

import 'dart:async';

import 'package:flutter/material.dart';

class AnimatedText extends StatefulWidget {
 final String text;
 final int delayInMilliseconds;
 final int durationInMilliseconds;
 final TextStyle textStyle;

 AnimatedText(this.text, this.delayInMilliseconds,
 {this.durationInMilliseconds: 2500, this.textStyle});

 @override createState() => new AnimatedTextState(text);
}

class AnimatedTextState extends State<AnimatedText>
 with SingleTickerProviderStateMixin {

 String currentText = "";

 final String text;

 AnimationController animationController;

 List<int> textRunes;
 int curIndex = 0;

 AnimatedTextState(this.text) {
 textRunes = text.runes.toList();
 }

 @override
 Future initState() async {
 animationController = new AnimationController(
 vsync: this,
 value: 0.0,
 lowerBound: 0.0,
 upperBound: textRunes.length.toDouble(),
 duration: new Duration(
 milliseconds: widget.durationInMilliseconds));

 animationController.addListener(() {
 if (animationController.value.toInt() == 0) {
 setState(() {
 currentText = new String.fromCharCode(textRunes[0]);
 });
 } else if (animationController.value.toInt() > curIndex &&
 animationController.value.toInt() < textRunes.length) {
 setState(() {
 curIndex = animationController.value.toInt();
 currentText += new String.fromCharCode(textRunes[curIndex]);
 });
 }
 });

 await
 new Future.delayed(new Duration(milliseconds: widget.delayInMilliseconds));
 animationController.forward();
 }

 @override
 void dispose() {
 animationController.dispose();
 super.dispose();
 }

 @override
 Widget build(BuildContext context) {
 return new Text(currentText, textAlign: TextAlign.left,
 style: widget.textStyle ??
 new TextStyle(fontWeight: FontWeight.w600, fontSize: 28.0),);
 }
}

AnimatedLocationsText文件

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:travel/animated_text.dart';

enum AnimationType {
 Character,
 SlideDown
}

class AnimatedLocationsText extends StatefulWidget {

 final int delayInMilliseconds;

 AnimatedLocationsText(this.delayInMilliseconds);

 @override
 State createState() => new _AnimationState();
}

class _AnimationState extends State<AnimatedLocationsText>
 with SingleTickerProviderStateMixin {

 AnimationController animationController;
 Animation<Alignment> londonSlideOut;
 Animation<double> londonFadeOut;

 Animation<Alignment> newYorkSlideIn;
 Animation<double> newYorkFadeIn;
 Animation<Alignment> newYorkSlideOut;
 Animation<double> newYorkFadeOut;

 Animation<Alignment> losAngelesSlideIn;
 Animation<double> losAngelesFadeIn;

 String firstLocation = "London";
 String secondLocation = "New York";
 String thirdLocation = "Los Angeles";

 @override
 void initState() {
 super.initState();

 animationController =
 new AnimationController(vsync: this, duration: new Duration(seconds: 6));

 londonSlideOut = new AlignmentTween(
 begin: new Alignment(-1.0, 0.0), end: new Alignment(-1.0, 1.0))
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.4, 0.45, curve: Curves.easeIn)));
 londonFadeOut = new Tween<double>(begin: 1.0, end: 0.0)
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.42, 0.45, curve: Curves.easeIn)));

 newYorkSlideIn = new AlignmentTween(
 begin: new Alignment(-1.0, -1.0), end: new Alignment(-1.0, 0.0),
 ).animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.42, 0.45, curve: Curves.easeIn)));
 newYorkFadeIn = new Tween<double>(begin: 0.0, end: 1.0)
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.42, 0.45)));

 newYorkSlideOut = new AlignmentTween(
 begin: new Alignment(-1.0, 0.0), end: new Alignment(-1.0, 1.0))
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.8, 0.85, curve: Curves.easeIn)));
 newYorkFadeOut = new Tween<double>(begin: 1.0, end: 0.0)
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.82, 0.85)));

 losAngelesSlideIn = new AlignmentTween(
 begin: new Alignment(-1.0, -1.0), end: new Alignment(-1.0, 0.0))
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.8, 0.85, curve: Curves.easeIn)));
 losAngelesFadeIn = new Tween<double>(begin: 0.0, end: 1.0)
 .animate(new CurvedAnimation(parent: animationController,
 curve: new Interval(0.82, 0.85)));

 londonSlideOut.addListener(() {
 setState(() {});
 });
 londonFadeOut.addListener(() {
 setState(() {});
 });

 newYorkSlideIn.addListener(() {
 setState(() {});
 });
 newYorkFadeIn.addListener(() {
 setState(() {});
 });

 newYorkSlideOut.addListener(() {
 setState(() {});
 });
 newYorkFadeOut.addListener(() {
 setState(() {});
 });

 losAngelesSlideIn.addListener(() {
 setState(() {});
 });
 losAngelesFadeIn.addListener(() {
 setState(() {});
 });

 new Future.delayed(
 new Duration(milliseconds: widget.delayInMilliseconds + 500))
 .then((_) {
 animationController.forward();
 });
 }

 @override
 void dispose() {
 animationController.dispose();
 super.dispose();
 }


 @override
 Widget build(BuildContext context) {
 return new SizedBox(
 height: 40.0,
 child: new Stack(
 children: <Widget>[
 // London
 new Align(
 alignment: londonSlideOut.value,
 child: new Opacity(
 opacity: londonFadeOut.value,
 child: new AnimatedText("London", widget.delayInMilliseconds,
 durationInMilliseconds: 500,
 textStyle: new TextStyle(color: Colors.green,
 fontSize: 24.0,
 fontWeight: FontWeight.w500),),
 ),
 ),
 // New York
 new AlignTransition(
 alignment: !(newYorkSlideIn.value.y == 0.0)
 ? newYorkSlideIn
 : newYorkSlideOut,
 child: new Opacity(
 opacity: !(newYorkFadeIn.value == 1.0)
 ? newYorkFadeIn.value
 : newYorkFadeOut.value,
 child: new Text(secondLocation, style: new TextStyle(
 color: Colors.lightBlue.withOpacity(0.7),
 fontSize: 24.0,
 fontWeight: FontWeight.w500),
 ),
 ),
 ),

 // Los Angeles
 new Align(
 alignment: losAngelesSlideIn.value,
 child: new Opacity(
 opacity: losAngelesFadeIn.value,
 child: new Text(thirdLocation, style: new TextStyle(
 color: Colors.purpleAccent,
 fontSize: 24.0,
 fontWeight: FontWeight.w500),),
 ),
 ),

 ],
 ),
 );
 }

}

AnimatedBackground文件

import 'package:flutter/material.dart';

class AnimatedBackground extends StatefulWidget {
 @override
 State createState() => new AnimatedBackgroundState();

}

class AnimatedBackgroundState extends State<AnimatedBackground>
 with SingleTickerProviderStateMixin {

 AnimationController animationController;
 Animation<double> imageSizeAnimation;
 Animation<double> imageSlideAnimation;

 @override
 void initState() {
 super.initState();

 animationController = new AnimationController(
 vsync: this, duration: new Duration(milliseconds: 6000));
 imageSizeAnimation = new Tween<double>(begin: 0.0, end: 1.0).animate(
 new CurvedAnimation(
 parent: animationController,
 curve: new Interval(0.0, 0.1, curve: Curves.bounceInOut)));
 imageSlideAnimation = new Tween<double>(begin: 0.0, end: 0.5).animate(
 new CurvedAnimation(parent: animationController,
 curve: new Interval(0.1, 1.0, curve: Curves.linear)));

 imageSlideAnimation.addListener(() {
 setState(() {});
 });
 animationController.forward();
 }

 @override
 void dispose() {
 animationController.dispose();
 super.dispose();
 }

 @override
 Widget build(BuildContext context) {
 return new Container(
 child: new Align(
 alignment: new Alignment(1.0, -0.3),

 child: new ClipPath(
 child: new Image(
 alignment: new Alignment(imageSlideAnimation.value, 0.0),
 width: 250.0 * imageSizeAnimation.value,
 height: 350.0 * imageSizeAnimation.value,
 image: new AssetImage("assets/bar.jpg"),
 fit: BoxFit.cover),
 clipper: new _AnimatedBackgroundImageClipper(),
 ),
 ),
 );
 }
}

class _AnimatedBackgroundImageClipper extends CustomClipper<Path> {
 @override
 Path getClip(Size size) {
 Offset ctrl;
 Offset end;

 Path path = new Path();
 path.moveTo(size.width, 0.0);

 path.lineTo(0.2 * size.width, size.height * 0.5 - 20);

 ctrl = new Offset(-0.35 * size.width, size.height);
 end = new Offset(0.6 * size.width, size.height * 0.95);
 path.quadraticBezierTo(ctrl.dx, ctrl.dy, end.dx, end.dy);

 path.lineTo(0.6 * size.width, size.height * 0.95);

 ctrl = new Offset(0.7 * size.width, size.height - 20);
 end = new Offset(0.8 * size.width, size.height * 0.9);
 path.quadraticBezierTo(ctrl.dx, ctrl.dy, end.dx, end.dy);

 path.lineTo(0.8 * size.width, size.height * 0.9);

 ctrl = new Offset(0.9 * size.width, size.height * 0.9 - 15);
 end = new Offset(size.width, size.height * 0.8);
 path.quadraticBezierTo(ctrl.dx, ctrl.dy, end.dx, end.dy);

 path.lineTo(size.width, size.height * 0.8);

 path.close();
 return path;
 }

 @override
 bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}

SplashPage文件

import 'dart:async';
import 'package:flutter/scheduler.dart' show timeDilation;
import 'package:flutter/material.dart';
import 'package:travel/circles.dart';

class SplashPage extends StatefulWidget {
 @override
 State createState() => new SplashPageState();
}

class SplashPageState extends State<SplashPage>
 with SingleTickerProviderStateMixin {

 final circleDiameter = 50.0;

 AnimationController controller1;
 Animation<double> translation1;
 Animation<double> scale1;
 Animation<double> translation1Reverse;
 Animation<double> scale1Reverse;

 Animation<double> translation2;
 Animation<double> scale2;
 Animation<double> translation2Reverse;
 Animation<double> scale2Reverse;

 Animation<double> translation3;
 Animation<double> scale3;
 Animation<double> translation3Reverse;
 Animation<double> scale3Reverse;

 Animation<double> translation4;

 double currentTranslation = 0.0;
 double currentScale = 1.0;

 @override
 void initState() {
 super.initState();

 controller1 =
 new AnimationController(vsync: this, duration: const Duration(seconds: 7));
 translation1 = new Tween<double>(begin: 50.0, end: -20.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.0, 0.14, curve: Curves.easeInOut)));
 scale1 = new Tween<double>(begin: 0.8, end: 0.4).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.0, 0.14, curve: Curves.linear)));

 translation1Reverse = new Tween<double>(begin: -20.0, end: 55.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.14, 0.28, curve: Curves.easeInOut)));
 scale1Reverse = new Tween<double>(begin: 0.4, end: 0.85).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.14, 0.28, curve: Curves.linear)));

 translation2 = new Tween<double>(begin: 55.0, end: -20.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.28, 0.42, curve: Curves.easeInOut)));
 scale2 = new Tween<double>(begin: 0.85, end: 0.4).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.28, 0.42, curve: Curves.linear)));

 translation2Reverse = new Tween<double>(begin: -20.0, end: 60.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.42, 0.57, curve: Curves.easeInOut)));
 scale2Reverse = new Tween<double>(begin: 0.4, end: 0.9).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.42, 0.57, curve: Curves.linear)));

 translation3 = new Tween<double>(begin: 60.0, end: -20.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.57, 0.71, curve: Curves.easeInOut)));
 scale3 = new Tween<double>(begin: 0.9, end: 0.4).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.57, 0.71, curve: Curves.linear)));

 translation3Reverse = new Tween<double>(begin: -20.0, end: 65.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.71, 0.85, curve: Curves.easeInOut)));
 scale3Reverse = new Tween<double>(begin: 0.4, end: 1.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.71, 0.85, curve: Curves.linear)));

 translation4 = new Tween<double>(begin: 65.0, end: 15.0).animate(
 new CurvedAnimation(parent: controller1,
 curve: new Interval(0.85, 1.0, curve: Curves.linear)));

 translation1.addListener(() {
 setCurrentTranslation(translation1);
 });
 scale1.addListener(() {
 setCurrentScale(scale1);
 });

 translation1Reverse.addListener(() {
 if (translation1.value == -20) {
 setCurrentTranslation(translation1Reverse);
 }
 });

 scale1Reverse.addListener(() {
 if (scale1.value == 0.4) {
 setCurrentScale(scale1Reverse);
 }
 });

 translation2.addListener(() {
 if (translation1Reverse.value == 55) {
 setCurrentTranslation(translation2);
 }
 });
 scale2.addListener(() {
 if (scale1Reverse.value == 0.85) {
 setCurrentScale(scale2);
 }
 });

 translation2Reverse.addListener(() {
 if (translation2.value == -20) {
 setCurrentTranslation(translation2Reverse);
 }
 });

 scale2Reverse.addListener(() {
 if (scale2.value == 0.4) {
 setCurrentScale(scale2Reverse);
 }
 });

 translation3.addListener(() {
 if (translation2Reverse.value == 60) {
 setCurrentTranslation(translation3);
 }
 });
 scale3.addListener(() {
 if (scale2Reverse.value == 0.9) {
 setCurrentScale(scale3);
 }
 });

 translation3Reverse.addListener(() {
 if (translation3.value == -20) {
 setCurrentTranslation(translation3Reverse);
 }
 });

 scale3Reverse.addListener(() {
 if (scale3.value == 0.4) {
 setCurrentScale(scale3Reverse);
 }
 });

 translation4.addListener(() {
 if (translation3Reverse.value == 65) {
 setCurrentTranslation(translation4);
 }
 });

 controller1.addStatusListener((status) {
 if (status == AnimationStatus.completed) {
 showLandingPage();
 }
 });

 controller1.forward();
 }

 void setCurrentTranslation(Animation<double> animation) {
 setState(() {
 currentTranslation = animation.value;
 });
 }

 void setCurrentScale(Animation<double> scaleAnimation) {
 setState(() {
 currentScale = scaleAnimation.value;
 });
 }

 @override
 void dispose() {
 controller1.dispose();
 super.dispose();
 }

 @override
 Widget build(BuildContext context) {
 final matrix1 = new Matrix4.translationValues(
 -1 * currentTranslation, 0.0, 0.0);
 matrix1.scale(currentScale, currentScale);
 final matrix2 = new Matrix4.translationValues(currentTranslation, 0.0, 0.0);
 matrix2.scale(currentScale, currentScale);

 return new Scaffold(
 body: new Center(
 child: new Hero(
 tag: "CircleHeroTag",
 child: new Stack(
 alignment: Alignment.center,
 children: <Widget>[
 new Transform(
 transform: matrix1,
 child: new Circle(
 color: Colors.purple, diameter: circleDiameter),
 ),
 new Transform(
 transform: matrix2,
 child: new Opacity(
 opacity: 0.8,
 child: new Circle(
 color: Colors.yellow, diameter: circleDiameter),
 ),
 )
 ],
 ),
 ),
 ),
 );
 }

 void showLandingPage() {
 new Future.delayed(new Duration(milliseconds: 500)).then((_) =>
 Navigator.of(context).pushNamed("/landing"));
 }

}

SpreadCircles文件

import 'package:flutter/material.dart';
import 'package:travel/circles.dart';

class SpreadCircles extends StatefulWidget {

 @override
 State createState() => new SpreadCirclesState();
}

class SpreadCirclesState extends State<SpreadCircles>
 with SingleTickerProviderStateMixin {

 AnimationController animationController;
 Animation<double> purpleCircleDiameter;
 Animation<double> yellowCircleDiameter;
 Animation<double> greenCircleDiameter;

 @override
 void initState() {
 super.initState();

 animationController =
 new AnimationController(
 vsync: this, duration: new Duration(milliseconds: 800));

 purpleCircleDiameter = new Tween<double>(begin: 0.0, end: 130.0).animate(
 new CurvedAnimation(parent: animationController,
 curve: new Interval(0.0, 0.6, curve: Curves.bounceInOut)));

 yellowCircleDiameter = new Tween<double>(begin: 0.0, end: 80.0).animate(
 new CurvedAnimation(parent: animationController,
 curve: new Interval(0.3, 0.7, curve: Curves.bounceInOut)));

 greenCircleDiameter = new Tween<double>(begin: 0.0, end: 60.0).animate(
 new CurvedAnimation(parent: animationController,
 curve: new Interval(0.6, 1.0, curve: Curves.easeIn)));

 purpleCircleDiameter.addListener(() {
 setState(() {});
 });

 greenCircleDiameter.addListener(() {
 setState(() {});
 });

 yellowCircleDiameter.addListener(() {
 setState(() {});
 });

 animationController.forward();
 }

 @override
 void dispose() {
 animationController.dispose();
 super.dispose();
 }

 @override
 Widget build(BuildContext context) {
 return new Container(
 color: Colors.transparent,
 child: new Stack(
 children: <Widget>[
 new Align( // light green circle on the left border
 alignment: new Alignment(-1.0, -0.05),
 child: new Circle(
 color: Colors.grey.withGreen(190).withOpacity(0.5),
 diameter: greenCircleDiameter.value,
 center: new Offset(10.0, 25.0),
 ),
 ),

 new Align( // purple circle on the right border
 alignment: new Alignment(1.0, 0.24),
 child: new Circle(
 color: Colors.purple.withOpacity(0.8),
 diameter: purpleCircleDiameter.value,
 center: new Offset(95.0, 75.0),
 ),
 ),

 new Align( // yellow circle at the top
 alignment: new Alignment(0.6, -0.85),
 child: new Circle(
 color: Colors.yellow.withOpacity(0.8),
 diameter: yellowCircleDiameter.value
 ),
 ),
 ],
 ),
 );
 }
}

StackedCircles文件

import 'package:flutter/material.dart';
import 'package:travel/circles.dart';

class StackedCircles extends StatelessWidget {

 final double circleDiameter;
 final Matrix4 circle1Transform;
 final Matrix4 circle2Transform;

 StackedCircles(this.circleDiameter,
 {this.circle1Transform, this.circle2Transform});

 @override
 Widget build(BuildContext context) {

 return new SizedBox(
 width: circleDiameter * 2,
 height: circleDiameter,
 child: new Stack(
 children: <Widget>[
 new Align(
 alignment: new Alignment(-0.5, 0.0),
 child: new Circle(color: Colors.purple, diameter: circleDiameter),
 ),
 new Align(
 alignment: new Alignment(0.5, 0.0),
 child: new Opacity(
 opacity: 0.8,
 child: new Circle(color: Colors.yellow, diameter: circleDiameter),
 ),
 ),
 ],
 ),
 );
 }
}

class StackedCirclesAnimation extends StatelessWidget {

 final Animation<double> controller;
 final Animation<double> diameter;
 final Animation<Alignment> alignment, alignment1;

 StackedCirclesAnimation({Key key, this.controller})
 :
 diameter = new Tween<double>(
 end: 25.0,
 begin: 30.0
 ).animate(new CurvedAnimation(parent: controller,
 curve: new Interval(0.0, 1.0, curve: Curves.ease))),

 alignment = new AlignmentTween(
 begin: new Alignment(-0.5, 0.0),
 end: new Alignment(0.2, 0.0),
 ).animate(new CurvedAnimation(parent: controller,
 curve: new Interval(0.0, 1.0, curve: Curves.ease))),

 alignment1 = new AlignmentTween(
 begin: new Alignment(0.5, 0.0),
 end: new Alignment(-0.2, 0.0),
 ).animate(new CurvedAnimation(parent: controller,
 curve: new Interval(0.0, 1.0, curve: Curves.ease))),

 super(key: key);

 Widget _buildAnimation(BuildContext context, Widget child) {
 return new Stack(
 children: <Widget>[
 new Align(
 alignment: alignment.value,
 child: new Circle(color: Colors.purple, diameter: diameter.value),
 ),
 new Align(
 alignment: alignment1.value,
 child: new Opacity(
 opacity: 0.8,
 child: new Circle(color: Colors.yellow, diameter: diameter.value),
 ),
 ),
 ],
 );
 }

 @override
 Widget build(BuildContext context) {
 return new AnimatedBuilder(
 builder: _buildAnimation,
 animation: controller,
 );
 }
}

总结

今天就分享到这里,代码大家可以直接新建一个项目,然后复制进去运行。

谢谢观看技术刚刚好的文章技术刚刚好是个人维护,每天至少更新一篇Flutter技术文章,实时为大家播报Flutter最新消息。如果你刚好也在关注Flutter这门技术,那就跟我一起学习进步吧,你的赞,收藏,转发是对我个人最大的支持,维护不易,欢迎关注。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表