blob: 9b3fe6730833e3d90a2788bc181c835dcd6e7ddf [file] [log] [blame]
// Copyright 2013 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';
import 'modal.dart';
/// The modal transition configuration for a Material fade transition.
///
/// The fade pattern is used for UI elements that enter or exit from within
/// the screen bounds. Elements that enter use a quick fade in and scale from
/// 80% to 100%. Elements that exit simply fade out. The scale animation is
/// only applied to entering elements to emphasize new content over old.
///
/// ```dart
/// /// Sample widget that uses [showModal] with [FadeScaleTransitionConfiguration].
/// class MyHomePage extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Center(
/// child: ElevatedButton(
/// onPressed: () {
/// showModal(
/// context: context,
/// configuration: FadeScaleTransitionConfiguration(),
/// builder: (BuildContext context) {
/// return _CenteredFlutterLogo();
/// },
/// );
/// },
/// child: Icon(Icons.add),
/// ),
/// ),
/// );
/// }
/// }
///
/// /// Displays a centered Flutter logo with size constraints.
/// class _CenteredFlutterLogo extends StatelessWidget {
/// const _CenteredFlutterLogo();
///
/// @override
/// Widget build(BuildContext context) {
/// return Center(
/// child: SizedBox(
/// width: 250,
/// height: 250,
/// child: const Material(
/// child: Center(
/// child: FlutterLogo(size: 250),
/// ),
/// ),
/// ),
/// );
/// }
/// }
/// ```
class FadeScaleTransitionConfiguration extends ModalConfiguration {
/// Creates the Material fade transition configuration.
///
/// [barrierDismissible] configures whether or not tapping the modal's
/// scrim dismisses the modal. [barrierLabel] sets the semantic label for
/// a dismissible barrier. [barrierDismissible] cannot be null. If
/// [barrierDismissible] is true, the [barrierLabel] cannot be null.
const FadeScaleTransitionConfiguration({
Color barrierColor = Colors.black54,
bool barrierDismissible = true,
Duration transitionDuration = const Duration(milliseconds: 150),
Duration reverseTransitionDuration = const Duration(milliseconds: 75),
String barrierLabel = 'Dismiss',
}) : super(
barrierColor: barrierColor,
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
transitionDuration: transitionDuration,
reverseTransitionDuration: reverseTransitionDuration,
);
@override
Widget transitionBuilder(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return FadeScaleTransition(
animation: animation,
child: child,
);
}
}
/// A widget that implements the Material fade transition.
///
/// The fade pattern is used for UI elements that enter or exit from within
/// the screen bounds. Elements that enter use a quick fade in and scale from
/// 80% to 100%. Elements that exit simply fade out. The scale animation is
/// only applied to entering elements to emphasize new content over old.
///
/// This widget is not to be confused with Flutter's [FadeTransition] widget,
/// which animates only the opacity of its child widget.
class FadeScaleTransition extends StatelessWidget {
/// Creates a widget that implements the Material fade transition.
///
/// The fade pattern is used for UI elements that enter or exit from within
/// the screen bounds. Elements that enter use a quick fade in and scale from
/// 80% to 100%. Elements that exit simply fade out. The scale animation is
/// only applied to entering elements to emphasize new content over old.
///
/// This widget is not to be confused with Flutter's [FadeTransition] widget,
/// which animates only the opacity of its child widget.
///
/// [animation] is typically an [AnimationController] that drives the transition
/// animation. [animation] cannot be null.
const FadeScaleTransition({
Key? key,
required this.animation,
this.child,
}) : super(key: key);
/// The animation that drives the [child]'s entrance and exit.
///
/// See also:
///
/// * [TransitionRoute.animate], which is the value given to this property
/// when it is used as a page transition.
final Animation<double> animation;
/// The widget below this widget in the tree.
///
/// This widget will transition in and out as driven by [animation] and
/// [secondaryAnimation].
final Widget? child;
static final Animatable<double> _fadeInTransition = CurveTween(
curve: const Interval(0.0, 0.3),
);
static final Animatable<double> _scaleInTransition = Tween<double>(
begin: 0.80,
end: 1.00,
).chain(CurveTween(curve: decelerateEasing));
static final Animatable<double> _fadeOutTransition = Tween<double>(
begin: 1.0,
end: 0.0,
);
@override
Widget build(BuildContext context) {
return DualTransitionBuilder(
animation: animation,
forwardBuilder: (
BuildContext context,
Animation<double> animation,
Widget? child,
) {
return FadeTransition(
opacity: _fadeInTransition.animate(animation),
child: ScaleTransition(
scale: _scaleInTransition.animate(animation),
child: child,
),
);
},
reverseBuilder: (
BuildContext context,
Animation<double> animation,
Widget? child,
) {
return FadeTransition(
opacity: _fadeOutTransition.animate(animation),
child: child,
);
},
child: child,
);
}
}