// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; /// Flutter code sample for [InteractiveViewer.transformationController]. void main() => runApp(const TransformationControllerExampleApp()); class TransformationControllerExampleApp extends StatelessWidget { const TransformationControllerExampleApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: TransformationControllerExample(), ); } } class TransformationControllerExample extends StatefulWidget { const TransformationControllerExample({super.key}); @override State<TransformationControllerExample> createState() => _TransformationControllerExampleState(); } /// [AnimationController]s can be created with `vsync: this` because of /// [TickerProviderStateMixin]. class _TransformationControllerExampleState extends State<TransformationControllerExample> with TickerProviderStateMixin { final TransformationController _transformationController = TransformationController(); Animation<Matrix4>? _animationReset; late final AnimationController _controllerReset; void _onAnimateReset() { _transformationController.value = _animationReset!.value; if (!_controllerReset.isAnimating) { _animationReset!.removeListener(_onAnimateReset); _animationReset = null; _controllerReset.reset(); } } void _animateResetInitialize() { _controllerReset.reset(); _animationReset = Matrix4Tween( begin: _transformationController.value, end: Matrix4.identity(), ).animate(_controllerReset); _animationReset!.addListener(_onAnimateReset); _controllerReset.forward(); } // Stop a running reset to home transform animation. void _animateResetStop() { _controllerReset.stop(); _animationReset?.removeListener(_onAnimateReset); _animationReset = null; _controllerReset.reset(); } void _onInteractionStart(ScaleStartDetails details) { // If the user tries to cause a transformation while the reset animation is // running, cancel the reset animation. if (_controllerReset.status == AnimationStatus.forward) { _animateResetStop(); } } @override void initState() { super.initState(); _controllerReset = AnimationController( vsync: this, duration: const Duration(milliseconds: 400), ); } @override void dispose() { _controllerReset.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).colorScheme.primary, appBar: AppBar( automaticallyImplyLeading: false, title: const Text('Controller demo'), ), body: Center( child: InteractiveViewer( boundaryMargin: const EdgeInsets.all(double.infinity), transformationController: _transformationController, minScale: 0.1, maxScale: 1.0, onInteractionStart: _onInteractionStart, child: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: <Color>[Colors.orange, Colors.red], stops: <double>[0.0, 1.0], ), ), ), ), ), persistentFooterButtons: <Widget>[ IconButton( onPressed: _animateResetInitialize, tooltip: 'Reset', color: Theme.of(context).colorScheme.surface, icon: const Icon(Icons.replay), ), ], ); } }