How to animate widget along a curved bezier path from start point to end point?

Issue

How do I move a widget position along a curved bezier path from one position to another? The effect I am after is similar to how Hero animation works across page transitions – but I just want to move a widget from one position to another using a curved bezier path and not across pages like Hero animation works.

I know how to move a widget from one position to another position using AnimatedPostioned widget, but I do not how to do this so that the path is curved/bezier.

enter image description here

Solution

I actually asked a similar question a while ago: How to add a control point (Bézier curve) between two Offsets?

But now we have null-safety so I modified the code there, and made a quick demo for you.

Full source code:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyHome()));
}

class MyHome extends StatefulWidget {
  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  Offset _end = Offset(300, 300);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo'),
      ),
      body: Stack(
        children: [
          TweenAnimationBuilder(
            tween: BezierTween(
              begin: Offset(0, 0),
              control: Offset(0, 300),
              end: _end,
            ),
            duration: Duration(seconds: 1),
            builder: (BuildContext context, Offset value, Widget? child) {
              return Positioned(
                left: value.dx,
                top: value.dy,
                child: FlutterLogo(),
              );
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _end = Offset.zero;
          });
        },
      ),
    );
  }
}

class BezierTween extends Tween<Offset> {
  final Offset begin;
  final Offset end;
  final Offset control;

  BezierTween({required this.begin, required this.end, required this.control})
      : super(begin: begin, end: end);

  @override
  Offset lerp(double t) {
    final t1 = 1 - t;
    return begin * t1 * t1 + control * 2 * t1 * t + end * t * t;
  }
}

Answered By – user1032613

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.