Search code examples
flutterflutter-animation

Flutter AnimatedSwitcher with SlideTransition


In this code i try to make a simple increasing number with SlideTransition but it doesn't work correctly, i could only use ScaleTransition successful. that means i want to increase number with SlideTransition

Gif example of what i want to create:

please see second part as animation

enter image description here

class TestScreen extends StatefulWidget {
  const TestScreen({super.key});

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> with SingleTickerProviderStateMixin {
  int num = 0;
  late final AnimationController _animationController = AnimationController(
      duration: Duration(milliseconds: 750),
      vsync: this)
    ..forward();

  static final offset1 = Tween<Offset>(begin: Offset.zero, end: Offset(0, -1));
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Container(
        width: double.infinity,
        height: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            AnimatedSwitcher(
              duration: Duration(milliseconds: 1000),
              transitionBuilder: (child, animation) => SlideTransition(
                position: (offset1).animate(animation),
                child: child,
              ),
              child: Text(
                key: ValueKey(num),
                '$num',
                style: TextStyle(color: Colors.black, fontSize: 64.0),
              ),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  num++;
                });
              },
              child: Text('increment'),
            ),
          ],
        ),
      ),
    );
  }
}

Solution

  • enter image description here

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    
    void fileMain() {
      runApp(
        const MaterialApp(
          home: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
      late AnimationController animatedController;
      late Timer timer;
    
      double milliseconds = 0;
    
      @override
      void initState() {
        animatedController = AnimationController.unbounded(
          vsync: this,
        );
        super.initState();
        timer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
          milliseconds += 500;
          animatedController.animateTo(
            milliseconds,
            duration: const Duration(milliseconds: 500),
          );
        });
      }
    
      @override
      void dispose() {
        animatedController.dispose();
    
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Padding(
              padding: const EdgeInsets.only(left: 120),
              child: AnimatedBuilder(
                animation: animatedController,
                builder: (context, child) {
                  final value = (animatedController.value / 100).ceil() / 10;
                  final map = value.toString().trim().split(".");
                  final animatedLetters = map[0].split("");
                  return Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      Container(
                          height: 10,
                          width: 10,
                          decoration: const BoxDecoration(
                              color: Colors.red, shape: BoxShape.circle)),
                      ...animatedLetters
                          .asMap()
                          .map(
                            (key, value) => MapEntry(
                              key,
                              AnimatedLetter(
                                key: ValueKey(key),
                                letter: value,
                              ),
                            ),
                          )
                          .values
                          .toList(),
                      Text(
                        '.${map[1]}',
                      ),
                    ],
                  );
                },
              ),
            ),
          ),
        );
      }
    }
    
    class AnimatedLetter extends StatefulWidget {
      const AnimatedLetter({super.key, this.letter});
    
      final String? letter;
    
      @override
      State<AnimatedLetter> createState() => _AnimatedLetterState();
    }
    
    class _AnimatedLetterState extends State<AnimatedLetter>
        with SingleTickerProviderStateMixin {
      AnimationController? controller;
    
      String? currentLetter;
      String? prevLetter;
    
      @override
      void initState() {
        controller = AnimationController(
          duration: const Duration(milliseconds: 300),
          vsync: this,
        );
        currentLetter = widget.letter;
        prevLetter = widget.letter;
        super.initState();
      }
    
      @override
      void didUpdateWidget(AnimatedLetter oldWidget) {
        if (widget.letter != oldWidget.letter) {
          setState(() {
            prevLetter = oldWidget.letter;
            currentLetter = widget.letter;
            controller!
              ..reset()
              ..forward();
          });
        }
    
        super.didUpdateWidget(oldWidget);
      }
    
      @override
      Widget build(BuildContext context) {
        return SizedBox(
          child: AnimatedBuilder(
              animation: controller!,
              builder: (_, __) {
                return Stack(
                  alignment: Alignment.centerRight,
                  children: [
                    Transform.translate(
                      offset: Offset(0, controller!.value * 20),
                      child: Opacity(
                        opacity: 1 - controller!.value,
                        child: Text(
                          prevLetter!,
                          textAlign: TextAlign.center,
                        ),
                      ),
                    ),
                    Transform.translate(
                      offset: Offset(0, -20 + controller!.value * 20),
                      child: Opacity(
                        opacity: controller!.value,
                        child: Text(
                          currentLetter!,
                          textAlign: TextAlign.center,
                        ),
                      ),
                    ),
                  ],
                );
              }),
        );
      }
    }