How can I create a circular animation with orbiting images in Flutter?

35 Views Asked by At

I'm trying to animate some images which should be orbited based on a circle.

example image

Here i1, i2, i3 and i4 are four image widgets which should change their position on any touch event in a clockwise way. As I'm new in flutter animation any kind of hints or explanation would be very helpful for me.

1

There are 1 best solutions below

0
noobEinstien On BEST ANSWER

Thanks for your question.

We can achieve this by using Flutter's AnimationController and the dart:math library. I will share the sample workaround here.

Two methods pop into my mind to achieve this, one is using custom UI and the other one is using the default Flutter framework widgets. I am going to use the Stack widget here.

Create a StatefulWidget

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

  @override
  State<OrbitingWidgets> createState() => _OrbitingWidgetsState();
}

class _OrbitingWidgetsState extends State<OrbitingWidgets>{

late AnimationController _controller;
@override
  void initState() {
    super.initState();

    // Create animation controller
    _controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 10), // Duration for one full rotation
    )..repeat();

  }


@override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // Central dot
        Center(
          child: Container(
            width: 10,
            height: 10,
            decoration: const BoxDecoration(
              color: Colors.red,
              shape: BoxShape.circle,
            ),
          ),
        ),
        // Orbiting widgets will be here
      ],
    );
  }

 @override
 void dispose() {
   _controller.dispose();
   super.dispose();
 }

}

Next, create AnimatedBuilder

Widget _buildOrbitingWidget(int index) {
    
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        double x = 0; // find the x displacement
        double y = 0; // find the y displacement

        return Positioned(
          left: MediaQuery.of(context).size.width / 2 + x,
          top: MediaQuery.of(context).size.height / 2 + y,
          child: Container(
            width: 20,
            height: 20,
            decoration: BoxDecoration(
              color: Colors.blue,
              shape: BoxShape.circle,
            ),
          ),
        );
      },
    );
  }

Next find the x position and y position

    /// For finding the x and y  point of the circle's outline we are using the below equation
    final radius  = 100;
    double x = cos(angle + _controller.value * 2 * pi) * radius;
    double y = sin(angle + _controller.value * 2 * pi) * radius;

Finally, we call the function in a for loop for as many children

  @override
  Widget build(BuildContext context) {
    return Stack(alignment: Alignment.center,
      children: [
        // Central dot
        Container(
          width: 10,
          height: 10,
          decoration: const BoxDecoration(
            color: Colors.red,
            shape: BoxShape.circle,
          ),
        ),
        // Orbiting widgets
        for (int i = 0; i < 10; i++) _buildOrbitingWidget(i),
      ],
    );
  }

The above code is tested and working I will post a video here sample code demo

You can optimize the code as you want. Also, you can implement it inside an InteractiveViewer if it is a big widget.

You. can wrap it inside RepaintBoundary to crop the parts as you showed in the question.

Thanks