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; int playTime = 10; double tm; @override void initState() { super.initState(); param = "beginning"; _controller = AnimationController( duration: Duration(seconds: playTime), vsync: this, )..addListener(() => contrVal()); } @override void dispose() { _controller?.dispose(); super.dispose(); } Future _startAnim() async { try { _controller.reset(); 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: [ Image.network( 'https://wallpaperplay.com/walls/full/e/5/3/13586.jpg', fit: BoxFit.cover, ), 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 ), // Container(width: 100, height: 100, decoration: BoxDecoration(color: Colors.black)), MovingHole( controller: _controller, time: playTime, ), ], ), ), Container( alignment: Alignment.bottomCenter, child: Text( "$param", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), )) ], ), )); } } class MovingHole extends StatefulWidget { MovingHole({Key key, this.controller, this.time}) : super(key: key); final int time; final AnimationController controller; @override _MovingHoleState createState() => _MovingHoleState(); } class _MovingHoleState extends State { _MovingHoleState(); AnimationController controller; List> scale = []; List> move = []; @override void initState() { super.initState(); controller = widget.controller; scale ..add(Tween(begin: 1.0, end: 0.5).animate( CurvedAnimation( parent: controller, curve: Interval(tu(0.5), tu(1.25), curve: Curves.easeOut), ), )) ..add(Tween(begin: 0.5, end: 1.2).animate( CurvedAnimation( parent: controller, curve: Interval( tu(3.5), tu(4.0), curve: Curves.ease, ), ), )); move ..add(Tween(begin: Offset(0, 20), end: Offset(-20, 100)).animate(CurvedAnimation( parent: controller, curve: Interval( tu(0.0), tu(0.5), curve: Curves.ease, ), ))) ..add(Tween(begin: Offset(50, 100), end: Offset(30, 20)).animate(CurvedAnimation( parent: controller, curve: Interval( 0.9, 1.0, curve: Curves.ease, ), ))); } double tu(double value) { return value / widget.time; } @override Widget build(BuildContext context) { Matrix4 allMoves = Matrix4.identity(); scale.forEach((item) { allMoves.scale(item.value); }); move.forEach((item) { allMoves.translate(item.value.dx, item.value.dy); }); return // AnimatedBuilder( // animation: controller, // builder: (BuildContext context, Widget child) { // return // // Container( // child: Transform( alignment: Alignment.topLeft, transform: allMoves, child: Container( // width: 60.0, // height: 10.0, decoration: BoxDecoration( shape: BoxShape.rectangle, color: Colors.black, // border: Border.all(color: color, style: BorderStyle.solid, width: 4.0 - (2 * controller.value)) // ), )), ); // }); } } // создать переменную, листенером слить текущее значение, на поляне в стеке вывести. // сколько составляет 0.05 от 10 секунд