🥦 Introduction – About Bezier curves

Bezier curve, this is a term that we’re all familiar with, especially in the front end, if you haven’t used it.

And I’m going to continue to talk a little bit about bezier curves:

Bezier curve is such a curve, it is a smooth curve drawn from the coordinates of four arbitrary points. In history, people who studied Bessel curves originally designed this vector curve drawing method based on the idea that four points were determined by the known parametric equation of the curve. Bessel curves are more interesting because of their “rubber band effect”, which means that as points move regularly, the curve will produce a change like rubber band extension, which brings a visual impact. In 1962, French mathematician Pierre Bezier was the first to study this vector curve drawing method, and gave a detailed calculation formula, so the curve drawn according to such a formula is named after his family name is Bezier curve. -Baidu.com

His appearance laid the foundation for computer vector graphics, so what can we do with it?

Some people said, a lot of online search, this is necessary, “wave shape”, “parabolic effect” and so on.

🍋 Effect and calculation formula of Bezier curve

I’m not going to talk about the difference between Bessel curves, but I’m going to post the effect and the formula.

First order Bezier curve

Second order Bezier curve

Third order Bezier curve

The rest of the higher order, which I will not repeat, can be inferred as follows:

🥝 to achieve goods add shopping cart effect

After reviewing the principles of bezier curves, let’s look at what we are going to achieve today:

Before the implementation

Before we do that, let’s make sure that we use a second-order Bezier curve to achieve the parabolic effect.

Parameters needed for second-order Bessel curve:

  1. The starting point p0
  2. The control points p1
  3. At the end of the p2

How to get the coordinate points first forget, then look at the picture, there is a very important place, is according to the parabola falling together with the “little red point”.

How should the “little red dot” appear? Let’s move on.

Begin to implement

Let’s start with the above image. Where to start?

1. Figure out where you start and where you finish

The page is very simple and the code is as follows:

Column(
  children: <Widget>[
    Expanded(
      child: ListView.builder(
        itemBuilder: (BuildContext context, int index) {
          return Row(
          	// Hide useless code
          );
        },
        itemCount: 100,
      ),
    ),
    Container(
      height: 1,
      color: Colors.grey.withOpacity(0.5),
    ),
    Container(
      height: 60,
      color: Colors.white,
      child: Row(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.only(left: 20),
            child: Icon(
              Icons.shop_two,
              key: _key,
            ),
          )
        ],
      ),
    )
  ],
)
Copy the code

A Column with a ListView at the top followed by a “shopping cart icon”.

The starting point is the + sign for each item in our ListView and the ending point is the “shopping cart icon” in the lower left corner.

The coordinates of the destination are easy to say, given a GlobalKey, then get the position in the first frame callback:

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((c) {
    // Get the location of the shopping cart
    _endOffset = (_key.currentContext.findRenderObject() as RenderBox)
      .localToGlobal(Offset.zero);
  });
}
Copy the code

What about the starting point?

Because the starting point is in the ListView and scrolling, many kids might say, “Why not give each icon a GlobalKey?

Are you sure you’re not killing me, kid?

GlobalKey uses a static constant Map to hold its corresponding Element. GlobalKey allows you to find the Widget, State, and Element that holds the GlobalKey. Note: GlobalKey is very expensive and should be used with caution.

– Vadaski – Flutter | a simple Key

If there were 10,000 listings at this point, wouldn’t it explode?

If we look at the code that fetched the location of the “shopping cart”, we are using the GlobalKey to fetch the context. If we use the context to fetch the location, why don’t we just use a component with the context?

The code is as follows:

Builder(
  builder: (context) {
    return IconButton(
      icon: Icon(Icons.add_circle_outline),
      onPressed: () {
        // Use the Builder component to get the context
        RenderBox box = context.findRenderObject();
        varoffset = box.localToGlobal(Offset.zero); }); },)Copy the code

Use the Builder directly to get the location of the component.

So we have the coordinates of where we start and where we end, what about the control points?

2. Set the control points of second-order Bezier curves

So that’s a little bit easier, and we can look at this:

(Hand broken painting, just look)

We can play this control point at will, depending on the effect of your decision, here is the following:

var x1 = widget.startPosition.dx - 250;
var y1 = widget.startPosition.dy - 100;
Copy the code

We have all the values we need for a second-order Bezier curve, and now we can figure out where we are.

3. Obtain the position of the red dot in each frame

We have the values of P0, P1, and P2. We can use the Tween of the Flutter to obtain the value of t. Finally, we can insert the formula:

@override
void initState() {
  super.initState();
  _controller =
    AnimationController(duration: Duration(milliseconds: 800), vsync: this);
  _animation = Tween(begin: 0.0, end: 1.0).animate(_controller);

  // Second order Bezier curve
  var x0 = widget.startPosition.dx;
  var y0 = widget.startPosition.dy;

  var x1 = widget.startPosition.dx - 250;
  var y1 = widget.startPosition.dy - 100;

  var x2 = widget.endPosition.dx;
  var y2 = widget.endPosition.dy;

  _animation.addListener(() {
    // t dynamically changing value
    var t = _animation.value;
    if (mounted)
      setState(() {
        left = pow(1 - t, 2) * x0 + 2 * t * (1 - t) * x1 + pow(t, 2) * x2;
        top = pow(1 - t, 2) * y0 + 2 * t * (1 - t) * y1 + pow(t, 2) * y2;
      });
  });

  // Initialize the position of the dot
  left = widget.startPosition.dx;
  top = widget.startPosition.dy;

  // The animation starts when the dot is displayed
  _controller.forward();
}
Copy the code

After the animation starts, you can get the position of the little red dot for each frame.

4. Show the little red dot

How do I show the little red dot? So what do you have to do when you click.

The first thing THAT came to my mind was to wrap IndexStack around it, set the position of the little red dot when I clicked on it, and then display it.

Then Overlay 😂 came to mind.

The code for the Button in the ListView is as follows:

IconButton(
  icon: Icon(Icons.add_circle_outline),
  onPressed: () {
    // Get the location of the current widget when clicked, passing in the overlayEntry
    var _overlayEntry = OverlayEntry(builder: (_) {
      RenderBox box = context.findRenderObject();
      var offset = box.localToGlobal(Offset.zero);
      return RedDotPage(
        startPosition: offset,
        endPosition: _endOffset,
      );
    });
    / / display Overlay
    Overlay.of(context).insert(_overlayEntry);
    // Wait for the animation to end
    Future.delayed(Duration(milliseconds: 800), () {
      _overlayEntry.remove();
      _overlayEntry = null; }); },)Copy the code

The RedDotPage is the page we defined as a little red dot, we pass it the starting point, we make the Overlay display, and when the Overlay is displayed, we start the bezier curve animation, and when the animation is over, we remove the OverlayEntry.

🍍 summary

This is all about adding a shopping cart with the Flutter implementation, with some details in it.

The code has been submitted to Github – Add Shopping cart Demo.

If there are defects, I hope you put forward, learn together! 🤝