flutter - создает эффект эластичности анимации
У меня есть контейнер в стекеwidget of height
100,0. It is positioned in the center using a
Позиционируем виджет следующим образом
Container(
width:100.0,
height:100.0,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned(
top: 40.0,
child: Container(
width: 20.0,
height: 20.0,
color: Colors.red,
),
)
],
)
)
Я хочу анимировать красный контейнер таким образом, чтобы при щелчке он переходил в нижнюю часть родительского контейнера, а при щелчке angain отскакивал назад вверх, а затем обратно в центр.
Я пытался с помощью Curves.elasticOut
но этого недостаточно для меня. Как мне добиться этого эффекта
2 ответа
Попробуйте этот код и дайте мне знать, правильно ли я понимаю вашу анимацию
Отредактировано:
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
import 'dart:math';
const BOX_COLOR = Colors.cyan;
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Spring Box",
theme: ThemeData(
primaryColor: Colors.red,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Padding(
child: PhysicsBox(),
padding: EdgeInsets.only(
left: 20.0,
right: 20.0,
top: 20.0,
bottom: 20.0,
),
),
));
}
}
class PhysicsBox extends StatefulWidget {
@override
BoxState createState() => BoxState();
}
class BoxState extends State<PhysicsBox> with TickerProviderStateMixin {
AnimationController controller;
AnimationController controller2;
Animation<double> animation;
SpringSimulation simulation;
double _position;
@override
void initState() {
super.initState();
simulation = SpringSimulation(
SpringDescription(
mass: 1.0,
stiffness: 100.0,
damping: 5.0,
),
400.0,
208.0,
-4000.0,
);
controller2 = AnimationController(vsync: this,duration: Duration(milliseconds: 70));
animation = Tween(begin: 200.0, end: 400.0).animate(controller2)
..addListener((){
if(controller2.status == AnimationStatus.completed){controller.reset();}
setState(() {
_position = animation.value;
});
});
controller = AnimationController(vsync: this,duration: Duration(milliseconds: 700))..forward()
..addListener(() {
if(controller.status == AnimationStatus.completed){controller2.reset();}
setState(() {
_position = simulation.x(controller.value);
});
print('${simulation.x(controller.value)}');
});
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
width:500.0,
height:500.0,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned(
top: _position,
child: GestureDetector(
onTap: (){
if (controller.status == AnimationStatus.completed) {
controller2.forward();//controller.reset();
}else{
controller.forward();}
},
child: Container(
width: 100.0,
height: 100.0,
color: Colors.red,
),
),
)
],
)
);
}
}
Используйте TweenMax для Flutter: https://pub.dartlang.org/packages/tweenmax
Оберните ваш контейнер с помощью GestureDetector, чтобы использовать Tap Gesture, затем замените ваш красный контейнер на TweenContainer:
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
import 'package:tweenmax/tweenmax.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Spring Box",
theme: ThemeData(
primaryColor: Colors.red,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
bool isClicked = false;
@override
Widget build(BuildContext context) {
TweenContainer redContainer = TweenContainer(
data: TweenData(
top: 40,
width: 20.0,
height: 20.0,
color: Colors.red,
),
);
return Scaffold(
body: GestureDetector(
child: Container(
width: 100.0,
height: 100.0,
margin: EdgeInsets.only(top: 100, left: 100),
color: Colors.yellow,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
redContainer
],
)
),
onTap: (){
// click first time, animate "redContainer" to bottom:
if(!isClicked){
TweenMax.to(
redContainer,
duration: 0.3,
ease: Curves.ease,
data: TweenData(
top: 80
)
);
} else { // click second time, animate "redContainer" to top:
TweenMax.to(
redContainer,
duration: 0.2,
ease: Curves.easeIn,
data: TweenData(
top: 0
),
onComplete: (redContainer){
// animate it back to center position:
TweenMax.to(
redContainer,
duration: 0.8,
ease: ElasticOutCurve(0.3),
data: TweenData(
top: 40
)
);
}
);
}
isClicked = !isClicked;
},
)
);
}
}
Смотрите это видео: https://drive.google.com/file/d/1i3BgxWiVna6kQMRKVgUEQDTW2QTlSXWo/view?usp=sharing