Sitelet https://github.com/gskinner/flutter_animate/issues/136
Skip to content

How to use different animations delay on appear than on going away #136

Description

@orestesgaolin

This is what I would like to achieve:

  1. When the widget appears I want the animation to be delayed by 500 ms and fade in for 300 ms
  2. When the widget disappears I want the animation to start immediately and fade out for 300 ms

Currently when using AnimatedOpacity I achieve it by simply calling setState after a dedicated Timer(Duration(milliseconds: 500)), but I would love to define this declaratively.

Is there a way to achieve it?

I achieved this effect using AnimatedOpacity as follows:

import 'dart:async';

import 'package:flutter/widgets.dart';

/// Widget that delays opacity change when widget
/// appears (in) or disappears (out)
class DelayedAnimatedOpacity extends StatefulWidget {
  const DelayedAnimatedOpacity({
    super.key,
    Duration? delayIn,
    Duration? delayOut,
    this.duration = const Duration(milliseconds: 500),
    required this.child,
    required this.visible,
  })  : delayIn = delayIn ?? const Duration(milliseconds: 500),
        delayOut = delayOut ?? Duration.zero;

  final Duration delayIn;
  final Duration delayOut;
  final Duration duration;
  final Widget child;
  final bool visible;

  @override
  State<DelayedAnimatedOpacity> createState() => _DelayedAnimatedOpacityState();
}

class _DelayedAnimatedOpacityState extends State<DelayedAnimatedOpacity> {
  bool visible = false;
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    if (widget.visible) {
      _timer = Timer(widget.delayIn, () {
        if (mounted) {
          setState(() {
            visible = true;
          });
        }
      });
    }
  }

  @override
  void didUpdateWidget(covariant DelayedAnimatedOpacity oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.visible != visible) {
      if (widget.visible) {
        _timer?.cancel();
        _timer = Timer(widget.delayIn, () {
          if (mounted) {
            setState(() {
              visible = true;
            });
          }
        });
      } else {
        _timer?.cancel();
        _timer = Timer(widget.delayOut, () {
          if (mounted) {
            setState(() {
              visible = false;
            });
          }
        });
      }
    }
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedOpacity(
      duration: widget.duration,
      opacity: visible ? 1 : 0,
      child: widget.child,
    );
  }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions