'How to implement Uniformly Accelerated Motion Formula into Flutter Animation

I tried to create a Flutter Web App that can simulate Uniformly Accelerated Motion. So, I create a circle as the simulation object and some buttons. When the user press the most right button and the most left button, it will change the value of x and y in Alignment() so the circle will change its position. Then, for the double arrow button, if you press it, it should "launch" the circle to the right and to the left, back and forth, until _velocity is equal to zero.

So I managed to create the method for the most right and the most left button, but I don't know how to create the method for the double arrow button. Here is what I've been doing:

            CircleAvatar(
                  backgroundColor: Colors.grey[300],
                  child: IconButton(
                    color: Colors.black,
                    onPressed: () => {
                      Timer.periodic(Duration(milliseconds: _duration),
                          (timer) {
                        if (isRight) {
                          setState(_addXValue);
                          if (_xValue > 1) {
                            isRight = false;
                          }
                        } else {
                          setState(_reduceXValue);
                          if (_xValue < -1) {
                            isRight = true;
                          }
                        }
                        _duration++;
                      })
                    },
                    icon: const Icon(Icons.keyboard_double_arrow_right),
                  ),
                ),

My idea was to create a Timer function so it will change the circle position in a duration of time. I used Timer because I thought I can update the duration at run-time so it will apply like Uniformly Accelerated Motion, which is the animation will start fast at the beginning and it will become slower as the time goes by until _velocity is zero. So, for now I use a constant duration for the Timer.

Here is my full source code:

import 'dart:async';

import 'package:flutter/material.dart';
import 'dart:math' as math;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double _xValue = 0.0;

  double _yValue = 1.0;

  double _degree = 0;

  int _velocity = 300;

  bool isRight = true;

  int? _duration;

  void _addXValue() {
    if (_velocity > 0 && _duration != null) {
      _velocity -= 1;
      _xValue += 0.1;
      _degree += 15;
      _duration = _duration! + 1;
    }
  }

  void _reduceXValue() {
    if (_velocity > 0 && _duration != null) {
      _velocity -= 1;
      _xValue -= 0.1;
      _degree -= 15;
      _duration = _duration! + 1;
    }
  }

  void _handleBallMovement(int _duration) {
    Timer.periodic(Duration(milliseconds: _duration), (timer) {
      if (isRight) {
        setState(_addXValue);
        if (_xValue > 1) {
          isRight = false;
        }
      } else {
        setState(_reduceXValue);
        if (_xValue < -1) {
          isRight = true;
        }
      }
    });
  }

  @override
  void initState() {
    _duration = _velocity > 0
        ? ((_velocity / (_velocity * 0.01)) - (_velocity * 0.1) + 10).floor()
        : 0;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // int _duration = _velocity > 0
    //     ? ((_velocity / (_velocity * 0.01)) - (_velocity * 0.1) + 10).floor()
    //     : 0;

    var ball = Padding(
      padding: const EdgeInsets.symmetric(horizontal: 32.0),
      child: AnimatedAlign(
        duration: const Duration(milliseconds: 100),
        alignment: Alignment(_xValue, _yValue),
        child: Transform.rotate(
          angle: _degree * math.pi / 180,
          child: Container(
            width: 100,
            height: 100,
            decoration: const BoxDecoration(
              shape: BoxShape.circle,
              color: Colors.red,
            ),
            child: const Center(
              child: Text(
                'BOLA INI BOI',
                style: TextStyle(
                  fontSize: 8.0,
                  color: Colors.white,
                ),
              ),
            ),
          ),
        ),
      ),
    );

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 800,
              height: 600,
              decoration: BoxDecoration(
                border: Border.all(
                  color: Colors.black,
                ),
              ),
              child: ball,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircleAvatar(
                  backgroundColor: Colors.grey[300],
                  child: IconButton(
                    color: Colors.black,
                    onPressed: () => setState(_reduceXValue),
                    icon: const Icon(Icons.arrow_left),
                  ),
                ),
                CircleAvatar(
                  backgroundColor: Colors.grey[300],
                  child: IconButton(
                    color: Colors.black,
                    onPressed: () => {},
                    icon: const Icon(Icons.keyboard_double_arrow_left),
                  ),
                ),
                Text("velocity: ${_velocity.toString()}"),
                SizedBox(width: 30),
                Text('xValue: ${_xValue.toString()}'),
                SizedBox(width: 30),
                Text('duration: $_duration'),
                CircleAvatar(
                  backgroundColor: Colors.grey[300],
                  child: IconButton(
                    color: Colors.black,
                    onPressed: () => {
                      _handleBallMovement(_duration!)
                      // Timer.periodic(Duration(milliseconds: _duration),
                      //     (timer) {
                      //   if (isRight) {
                      //     setState(_addXValue);
                      //     if (_xValue > 1) {
                      //       isRight = false;
                      //     }
                      //     _duration += 50;
                      //   } else {
                      //     setState(_reduceXValue);
                      //     if (_xValue < -1) {
                      //       isRight = true;
                      //     }
                      //     _duration += 50;
                      //   }
                      // })
                    },
                    icon: const Icon(Icons.keyboard_double_arrow_right),
                  ),
                ),
                CircleAvatar(
                  backgroundColor: Colors.grey[300],
                  child: IconButton(
                    color: Colors.black,
                    onPressed: () => setState(_addXValue),
                    icon: const Icon(Icons.arrow_right),
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }
}

Sorry for my bad english.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source