import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'dart:async'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp(home: Scaffold(body: App())); } } class App extends StatefulWidget { @override AppState createState() => AppState(); } class AppState extends State with SingleTickerProviderStateMixin { AnimationController _controller; String param; double tm; @override void initState() { super.initState(); param = "beginning"; _controller = AnimationController( duration: Duration(seconds: 3), vsync: this, )..addListener(() => contrVal()); } double timeM(double scene) { int time = 10; return scene / time; } @override void dispose() { _controller?.dispose(); super.dispose(); } Future _startAnim() async { try { await _controller.forward().orCancel; // await _controller.reverse().orCancel; } on TickerCanceled { print('welp we fucked'); } } contrVal() { setState(() { tm = _controller.value; if (_controller.value >= 0.2) param = 'two seconds'; if (_controller.value >= 0.5) param = "five seconds"; if (_controller.value >= 1) param = "ten seconds"; }); } @override Widget build(BuildContext context) { return Material( child: GestureDetector( onTap: () { _startAnim(); }, child: Stack( fit: StackFit.expand, children: [ // Container(child: Image(image: AssetImage('assets/scrns/scrn1.png'))), ColorFiltered( colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.8), BlendMode.srcOut), // This one will create the magic child: Stack( fit: StackFit.expand, children: [ Container( decoration: BoxDecoration( color: Colors.black, backgroundBlendMode: BlendMode .dstOut), // This one will handle background + difference out ), MovingHole(controller: _controller), ], ), ), Container( alignment: Alignment.bottomCenter, child: Text( "$param - $tm", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), )) ], ), )); } } class MovingHole extends StatelessWidget { static double timeM(double scene) { int time = 10; return scene / time; } MovingHole({Key key, this.controller}) : // scale1 = Tween(begin: 0.5, end: 0.5).animate( // CurvedAnimation( // parent: controller, // curve: Interval(timeM(0.5), 0.075, curve: Curves.easeOut), // ), // ), // scale2 = Tween(begin: 0.5, end: 1.2).animate( // CurvedAnimation( // parent: controller, // curve: const Interval( // 1, // 0.55, // curve: Curves.ease, // ), // ), // ), move1 = Tween(begin: Offset(0, 20), end: Offset(-20, 100)) .animate(CurvedAnimation( parent: controller, curve: const Interval( 0.0, 0.1, curve: Curves.ease, ), )), move2 = Tween(begin: Offset(50, 100), end: Offset(30, 20)) .animate(CurvedAnimation( parent: controller, curve: const Interval( 0.9, 1.0, curve: Curves.ease, ), )), super(key: key); final AnimationController controller; // final Animation scale1; // final Animation scale2; final Animation move1; final Animation move2; final Color color = Colors.black; // final Size size; @override Widget build(BuildContext context) { return AnimatedBuilder( animation: controller, builder: (BuildContext context, Widget child) { return Container( child: Transform( alignment: Alignment.topCenter, transform: Matrix4.identity() // ..scale( // scale1.value, // ) // ..scale(scale2.value) ..translate( move1.value.dx, move1.value.dy, ) ..translate( move2.value.dx, move2.value.dy, ), // child: Opacity( // opacity: opacityAnimation.value, child: Container( margin: EdgeInsets.all(80), // width: 50, // height: 10, decoration: BoxDecoration( color: color, border: Border.all( color: color, style: BorderStyle.solid, // width: 4.0 - (2 * controller.value)) ), )), )); }); } } // создать переменную, листенером слить текущее значение, на поляне в стеке вывести. // сколько составляет 0.05 от 10 секунд