aagarwal1012 / Animated-Text-Kit

🔔 A flutter package to create cool and beautiful text animations. [Flutter Favorite Package]
https://animated-text-kit.web.app
MIT License
1.66k stars 304 forks source link

How to several texts animation can be synchronized? #191

Open akbarpulatov opened 3 years ago

akbarpulatov commented 3 years ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like A clear and concise description of what you want to happen.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context Add any other context or screenshots about the feature request here.

aagarwal1012 commented 3 years ago

@akbarpulatov, can you describe your issues in detail?

akbarpulatov commented 3 years ago

For example i have Column of Texts which should start animation synchronously.

SirusCodes commented 3 years ago

This would require use of controller ig @aagarwal1012

subhangi2731 commented 3 years ago

can you assign this to me?

aagarwal1012 commented 3 years ago

@subhangi2731, sure you can work on this issue.

awhitford commented 3 years ago

I anticipate that this is minor code refactoring, so this is GSSOC Level 2.

My initial reaction is to give people the option to supply their own Animation Controller to AnimatedTextKit. (Right now, the Animation Controller is managed by AnimatedTextKit.)

akbarpulatov commented 3 years ago

I think it is better to give Controller Class, and Animation Controller keep inside. If we give Animation Controller, then user has to do a lot of boilerplate code. Controller class controls Animation Controller. I started this implementation. What is your opinion to this approach?

awhitford commented 3 years ago

@akbarpulatov I'm honestly unclear why a wrapper class (Controller) around the Animation Controller would add value, but I'm happy to keep an open mind. Show me some code and I can either appreciate the merit, or raise my concerns.

This problem reminds me of something I've worked with in Flutter Form Builder, specifically how it deals with TextEditingController: https://github.com/danvick/flutter_form_builder/blob/d51a870fe047423fcc5a137d932991af7b702c64/lib/src/fields/form_builder_text_field.dart#L454-L469 In a nutshell, it offers the option to supply a TextEditingController. When one is not provided, it will create one (and destroy it). I am imagining the same approach for AnimationController. However, if you have a better idea, let's see it.

SirusCodes commented 3 years ago

What I was think is to let the package control the AnimationController and the package will provide with another controller which user can use to controller animations such as start, pause and stop.

akbarpulatov commented 3 years ago

The first thing, came to my mind is:

class AnimatedTextController {
  AnimatedTextController();

  _AnimatedTextKitState _state = _AnimatedTextKitState();
  // bool get isAttached => _AnimatedTextKitState != null;

  void addState(_AnimatedTextKitState animatedTextKitState) {
    this._state = animatedTextKitState;
  }

  start(){
    _state.start();
  }

  pause(){
    _state.pause();
  }

  stop(){
    _state.stop();
  }
}

And in the _AnimatedTextKitState:

  start(){
    _controller.forward();
  }

  pause(){
    _controller.stop();
  }

  stop(){
    _controller.reset();
  }

here is my main:

import 'package:flutter/material.dart';
import 'package:animated_text_kit/animated_text_kit.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Text Kit',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final animatedTextController = AnimatedTextController();
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            SizedBox(
              width: double.infinity,
              child: ColorizeAnimatedTextKit(
                animatedTextController: animatedTextController,
                isRepeatingAnimation: true,
                repeatForever: true,
                onTap: () {
                  print("Tap Event");
                },
                text: [
                  "12345678912345",
                ],
                textStyle: TextStyle(fontSize: 50.0, fontFamily: "Horizon"),
                colors: [
                  Colors.purple,
                  Colors.blue,
                  Colors.yellow,
                  Colors.red,
                ],
                textAlign: TextAlign.start,
              ),
            ),
            SizedBox(
              width: double.infinity,
              child: ColorizeAnimatedTextKit(
                animatedTextController: animatedTextController,
                repeatForever: true,
                isRepeatingAnimation: true,
                onTap: () {
                  print("Tap Event");
                },
                text: [
                  "1234567891234",
                ],
                textStyle: TextStyle(fontSize: 50.0, fontFamily: "Horizon"),
                colors: [
                  Colors.purple,
                  Colors.blue,
                  Colors.yellow,
                  Colors.red,
                ],
                textAlign: TextAlign.start,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          FloatingActionButton(
            onPressed: () {
              animatedTextController.start();
            },
            child: const Icon(
              Icons.play_circle_outline_outlined,
              size: 50.0,
            ),
          ),
          SizedBox(height: 5),
          FloatingActionButton(
            onPressed: () {
              animatedTextController.pause();
            },
            child: const Icon(
              Icons.pause_circle_outline_outlined,
              size: 50.0,
            ),
          ),
          SizedBox(height: 5),
          FloatingActionButton(
            onPressed: () {
              animatedTextController.stop();
            },
            child: const Icon(
              Icons.stop_circle_outlined,
              size: 50.0,
            ),
          ),
        ],
      ),
    );
  }
}

Now tested the code. It has a bug to control only one Widget, cause controller is storing only one state object.

https://user-images.githubusercontent.com/27597344/111066933-6b71e100-84e3-11eb-84aa-bb7afe04953b.mov

awhitford commented 3 years ago

It has a bug to control only one Widget, cause controller is storing only one state object.

The original request is to have a way to synchronize multiple animations, so that issue is not really being addressed. The fact that the AnimationController is part of the _AnimatedTextKitState is the key issue. Right now, with two animations, we have two AnimationController instances.

I could see your AnimatedTextController trying to control many underlying AnimationController instances for a List of _AnimatedTextKitState. However, I think that is really a bad idea compared to having many _AnimatedTextKitState instances reference one AnimationController. (If you called start for many Animation Controllers, they all wouldn't start at exactly the same time. They may be close, but not exact.)

SirusCodes commented 3 years ago

@akbarpulatov this is what came in my mind honestly but looking at what @awhitford said I think implementing AnimationController would be easier and having one instance of will be more performant(I'm not sure about it but it feels so).

We can add a named constructor which will take AnimationController as a param

akbarpulatov commented 3 years ago

@awhitford, @SirusCodes, I agree with you. Giving AnimationController will be more effective. Thank you @awhitford Very nice accent on synchronization.

subhangi2731 commented 3 years ago

@akbarpulatov can you please guide me little bit on this?

awhitford commented 3 years ago

@subhangi2731 I recommend taking a look at this comment:

This problem reminds me of something I've worked with in Flutter Form Builder, specifically how it deals with TextEditingController: https://github.com/danvick/flutter_form_builder/blob/d51a870fe047423fcc5a137d932991af7b702c64/lib/src/fields/form_builder_text_field.dart#L454-L469 In a nutshell, it offers the option to supply a TextEditingController. When one is not provided, it will create one (and destroy it). I am imagining the same approach for AnimationController. However, if you have a better idea, let's see it.

I think the parallel of optionally supplying a TextEditingController is a reasonable model for optionally supplying an AnimationController. I think this is a small adjustment to be made to AnimatedTextKit. We will also need a test case to exercise this optional functionality.