Felix Kling

Felix Kling

1572320180

Particle Systems (for Puffs and Zaps) with Flutter

“He doesn’t look like I thought he would look”, you thought. Shaking his firm hand you noticed small reddish dots from chemical burns all over his arm. You were distracted by his discouragingly white shirt and haven’t noticed a small wooden box was shovelled under the table by his left leg. Well, you wouldn’t expect a practising magician to turn to a business meeting in a tailcoat, top hat and with a rabbit in one his white gloves. Reality is always a middle ground of sorts. And you can only imagine what was his image of you as a software engineer.

You two sat together on a shamelessly soft sofa and outlined the future project in high-level details. You could express it with one word — e-commerce.
Particle Systems (for Puffs and Zaps) with Flutter

But there were some very interesting specifics to this one. In his own words, he wanted to have a little bit of “puff” ☁️ to the most important actions on the application pages. So that it would have a little bit of “prestige” to it. He explained that it wasn’t strictly necessary for his audience, but would add bonus points compared with the competition. You couldn’t agree more and haven’t pay any conscious attention to quiet noise from under the table.

He also said that it would be good to have some “zap” ⚡️ during checkout workflows to make the user feel more magical already, even before their supplies had shipped. What a wonderful idea, you though whilst a tiny fraction of your consciousness recorded quiet chirping sounds from somewhere below.

So your working plan for next phase looks like:

  1. a little bit of ☁️
  2. some ⚡️

Particle Systems (for Puffs and Zaps) with Flutter

Particle Systems (for Puffs and Zaps) with Flutter

And it becomes apparent to you that you want particles. From your past experience, particles are a silver bullet when it comes to playful interaction. Magic is playful.

You start as usual: flutter create magic , then cd magic and code .. Then you Ctrl+P a pubspec.yaml and hit Ctrl+S so that IDE could initialise all the dependencies. When flutter pub get is finished in Debug console, you simply hit F5, choose the Flutter & Dart option, then hit Enter and select one of the emulators you’re using for development.

Simple and sweet, you think, without even realising that you just hit 51 keys on your keyboard in a row to scaffold the app. What a wonderful device is within your skull!
Particle Systems (for Puffs and Zaps) with Flutter

You go to dribbble to check what not to do with an application interface to make it obsolete in two months after a new design trend emerges and after a couple of delightful hours end up with the basic application prototype (initial sources for tutorial under the link).
Particle Systems (for Puffs and Zaps) with Flutter

So, you need particles. Well, you think, let’s start with one.

class Particle {
  double x;
  double y;

  Particle({ this.x, this.y });
}

But then, you realise that as per your previous experience it’s better to base abstract classes on their supposed behaviour rather properties. So, you think a bit more and remove the x and y from Particle. And making it abstract by itself. As the only thing which you could think of would be common in this system is that you’ll draw the particles on a Canvas .

abstract class Particle {
  void draw(Canvas canvas);
}

But then it comes to you that you may want to draw other things on your canvas too and it might be useful to mark this behaviour for all of them in a consistent fashion, so you end up with renaming this implementation from Particle to Drawable.

mixin Drawable {
  void draw(Canvas canvas);
}

You look to a ⌚️ and see that you already spent almost 5 minutes yet achieved nothing significant with particles. So you decide to go ballistic and actually draw something when the user taps any of the OutlineButton in the app.

Ok, you think, let it be a simple circle, for now.

mixin Drawable {
  void draw(Canvas canvas);
}

class Circle with Drawable {
  @override
  void draw(Canvas canvas) {
    canvas.drawCircle(Offset.zero, 20, Paint()..color = Colors.white);
  }
}

In a second or so after, your brain suggests you adding a CustomPainter which is capable of drawingDrawables.

class DrawablePainter extends CustomPainter {
  final Drawable child;

  DrawablePainter({this.child});

  @override
  void paint(Canvas canvas, Size size) {
    child.draw(canvas);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

Then you realize the brain didn’t suggest that out of the blue and update OutlineButton to draw this Circle , by adding a CustomPaint as a root widget in its build with new and shiny DrawablePainter as painter.

class OutlineButton extends StatelessWidget {
  final Widget child;
  final void Function() onPressed;

  const OutlineButton({
    @required this.child,
    @required this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    final borderRadius = BorderRadius.circular(32.0);

    return CustomPaint(
      painter: DrawablePainter(child: Circle()),
      child: ClipRRect(
        borderRadius: borderRadius,
        child: RawMaterialButton(
          onPressed: onPressed,
          child: Container(
              child: child,
              decoration: BoxDecoration(
                borderRadius: borderRadius,
                border: Border.all(
                  color: Colors.white,
                  width: 3.0,
                ),
              )),
        ),
      ),
    );
  }
}

And sure enough, you see a white circle overlaying the button in the UI.
Particle Systems (for Puffs and Zaps) with Flutter

“That is something already,” zips through your head. But something deep within your stomach tells you you’re far from finished. After a brief googling session, you find that they call it a “Gut feeling”, not that you haven’t felt them earlier.

“I want this to be centered” is your next thought. You see that there’s Size available for CustomPainter#draw. So it’s time to extend Drawable a bit to match that signature.

mixin Drawable {
  // Adding support for [Size]
  void draw(Canvas canvas, Size size);
}

class Circle with Drawable {
  // Updating signature to expect [Size] to be available
  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawCircle(Offset.zero, 20, Paint()..color = Colors.white);
  }
}

class DrawablePainter extends CustomPainter {
  final Drawable child;

  DrawablePainter({this.child});

  @override
  void paint(Canvas canvas, Size size) {
    // Passing [Size] down the chain
    child.draw(canvas, size);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

Particle Systems (for Puffs and Zaps) with Flutter

After that, it’s time for 🔗 chains! Whenever you are building complex systems with multi-layer behavior you always try to express each possible layer separately, so it’s possible to composite them later in whatever order. To apply that for alignment, you create a new Drawable, called Centered, which could contain other Drawable as its child. You implement alignment itself by using Canvas layering with canvas.save() and canvas.restore() , which as you know from experience is an extremely powerful technique which could bring your drawing as code to a whole new level.

class Centered with Drawable {
  final Drawable child;

  Centered({this.child});

  @override
  void draw(Canvas canvas, Size size) {
    canvas.save();
    canvas.translate(size.width / 2, size.height / 2);
    child.draw(canvas, size);
    canvas.restore();
  }
}

After that, you simply wrap your Circle with Centered and it starts looking very similar to the usual Flutter code.

// in OutlineButton.build
// ...
painter: DrawablePainter(
  child: Centered(
    child: Circle()
  ),
),
// ...

Particle Systems (for Puffs and Zaps) with Flutter

Then, you think a tiny bit more and decide to make use of awesome Flutter built-in: [Alignment](https://api.flutter.dev/flutter/painting/Alignment-class.html). As it would allow you to use the same nice and readable syntax as you get used to in Stack, and make use of the system even closer to “native” Fluter look. So, new Drawable, would take an Alignment object as part of the config and would render it’s Drawable child accordingly, very similar to how it was done by Centered.

class Aligned with Drawable {
  final Alignment alignment;
  final Drawable child;

  Aligned({
    this.alignment = Alignment.center,
    this.child,
  });

  @override
  void draw(Canvas canvas, Size size) {
    var offset = alignment.alongSize(size);

    canvas.save();
    canvas.translate(offset.dx, offset.dy);
    child.draw(canvas, size);
    canvas.restore();
  }
}

And you also swap Centered to Aligned in OutlinteButton and try different alignment options: Alignment.topCenter , Alignment.bottomRight , etc. to see how it changes the behaviour.

// in OutlineButton.build
// ...
child: Aligned(
  alignment: Alignment.center
  child: Circle(),
),
// ...

Particle Systems (for Puffs and Zaps) with Flutter
You feel that this system is ready for the next step: animations.

Previously, you have used AnimationController to animate things with Flutter and don’t want this case to be an exception. So what you want to do is somehow start redrawing the CustomPainter when AnimationController frame is ready.

You put your 🤔 face on, but only for as long as it took you to think “There should be a widget for that”.

Sure enough, just less than a minute later, here it is, right in a new tab of your browser: AnimatedBuilder. The core essence of that one is that it takes an AnimationController (just what you want, nice), and rebuilds as soon as it’s being animated.

Great power comes out of greater simplicity creating immense extendability, as it often happens in software.

Your next move is to add a new sibling to Drawable. Without any overthinking (just around 5 minutes spent on naming), you call it Updatable. You just want it to take your AnimationController and… do its magic, whatever.

mixin Updatable {
  void update(Animation animation);
}

You’re opting into implementing fading as first animated behavior, cause it’s simple, and opacity could behave exactly like AnimationController value , just change from 0 to 1.

So, Fading would behave as following, when update is called, it would simply set its opacity to the value of AnimationController. Simple and sweet, you definitely kissed it.

mixin Fading on Updatable {
  double opacity = 0.0;

  @override
  void update(Animation controller) {
    opacity = controller.value;
  }
}

And now, you’re linking it with Drawable behaviour, by creating a new class to utilize this mixin: FadingRect. You want that one to draw a Rect with opacity from Fading.

class FadingRect with Drawable, Updatable, Fading {
  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawRect(
      Rect.fromCenter(center: Offset.zero, width: 10, height: 10),
      Paint()..color = Colors.white.withOpacity(opacity),
    );
  }
}

Just as you hit Enter one last line to finish typing this code, your sight stops for a fraction of second on a tab where you searched for “Gut feeling”. And you think that this FadingRect has a lot of guts to hide from outlying users of it. Your next thought is simple and clear, “Hide the guts”. You decide that’s it’s a good time to actually name all these components combined after what they are. So you create your first blueprint of a Particle.

abstract class Particle implements Drawable, Updatable {
  @override
  void draw(Canvas canvas, Size size) {
    // Does nothing by default
  }

  @override
  void update(Animation controller) {
    // Does nothing by default
  }
}

Despite the class being abstract, you leave implementations of Drawable and Updatable explicitly empty. You find it useful that classes extending Particle won’t have to explicitly implement them all the time.

With that, you rewrite the FadingRect to be based on a Particle.

class FadingRect extends Particle with Fading {
  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawRect(
      Rect.fromCenter(center: Offset.zero, width: 10, height: 10),
      Paint()..color = Colors.white.withOpacity(opacity),
    );
  }
}

You can’t stop yourself from reading the declaration. Fading rect extends particle with fading. It looks like a definition on its own and you like when it’s possible to write code that expressive.

That code almost distracted you from the fact that DrawablePainter doesn’t know what Particle is and can’t work with AnimationController. “World needs a new hero,” booms in your head.

class ParticlePainter extends CustomPainter {
  final Animation controller;
  final Particle particle;

  ParticlePainter({@required this.controller, @required this.particle}) {
    particle.update(controller);
  }

  @override
  void paint(Canvas canvas, Size size) {
    particle.draw(canvas, size);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

World meets new hero without enthusiasm you’d expect. In fact, you’re the only one to witness its birth, and will probably remain an only person knowing of its existence. What a lonely hero you’ve just created.

To make its life a bit less miserable, you think it could use a friend. A Flutter-friend. A parent widget, to be more precise. You don’t want to mess with creating new SingleTickerProviderStateMixin or limit yourself to use only StatefulWidget for your particles, so you decide to create a wrapper which would make creating Puffs and Zaps a bit easier.

So, as you usually do, first of all, you write the code showing how would you like to use it. Or, as smart guys call, API-driven design.

class SimpleParticles extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Particles(
        child: Container(
          color: Colors.red,
        ),
        particle: Aligned(
          child: FadingRect(),
        ),
      ),
    );
  }
}

So, you just want to have a widget which would take another widget as a child, and a particle which would be drawn somehow. That’s a good start, but then you realise that calling code would most likely want to control when particles are appearing.

That is same as calling child widget methods from a parent widget. In Flutter it could be solved by either using [Key](/flutter/keys-what-are-they-good-for-13cb51742e7d) to obtain a reference to children state, or by using builder property pattern. You choose the latter as it assumes fewer restrictions on the client code part. So, instead of passing child to Particles, you pass builder.

For client code to know what to expect, you define a signature for your builder using the awesome [typedef](https://dart.dev/guides/language/language-tour#typedefs) feature.

typedef ParticlesWidgetBuilder = Widget Function(
  BuildContext context,
  AnimationController controller,
);

It would allow client code to make awful things to an AnimationController, to make it spill value in all directions and speeds.

With that in mind, the simplest example evolves slightly more complex simplest example.

class SimpleParticles extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Particles(
        builder: (context, controller) {
          return Container(
            color: Colors.red,
          );
        },
        particle: Aligned(
          child: FadingRect(),
        ),
      ),
    );
  }
}

So, now widget from within the builder could call controller.forward() whenever it’s a good time to start animating the Particles.

You want to illustrate that behavior a bit more details to yourself, so rewrite it with actually using the controller.

class SimpleParticles extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Particles(
        builder: (context, controller) {
          return RawMaterialButton(
            onPressed: () {
              controller.forward();
            },
            child: Text('Fade the rect!'),
          );
        },
        particle: Aligned(
          child: FadingRect(),
        ),
      ),
    );
  }
}

Having such an example, now it’s the easiest part left, to actually implement the Particles to behave in a way you just described.

You start with a scaffold of the basic scaffold from [AnimatedBuilder](https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html) docs and simply swap its builder to return the ParticlePainter instead. And then use the builder on Particles for obtaining a child for AnimatedBuilder.

class Particles extends StatefulWidget {
  final Duration duration;
  final Particle particle;
  final ParticlesWidgetBuilder builder;

  const Particles({this.particle, this.duration, this.builder});

  @override
  _ParticlesState createState() => _ParticlesState();
}

class _ParticlesState extends State<Particles>
    with SingleTickerProviderStateMixin {
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(vsync: this, duration: widget.duration);
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, child) {
        return CustomPaint(
          child: child,
          painter: ParticlePainter(
            controller: controller,
            particle: widget.particle,
          ),
        );
      },
      child: widget.builder(context, controller),
    );
  }
}

And then modify OutlineButton.build slightly to use this new interface for Particles.

// in OutlineButton.build
// ...
return Particles(
  duration: const Duration(seconds: 1),
  builder: (context, controller) {
    return ClipRRect(
      borderRadius: borderRadius,
      child: RawMaterialButton(
        onPressed: () {
          controller.forward();
          onPressed();
        },
        child: Container(
          child: child,
          decoration: BoxDecoration(
            borderRadius: borderRadius,
            border: Border.all(
              color: Colors.white,
              width: 3.0,
            ),
          ),
        ),
      ),
    );
  },
  particle: Aligned(
    child: FadingRect()
  ),
);
// ...

Particle Systems (for Puffs and Zaps) with Flutter

After adding it to OutlineButton instead of DrawablePainter, it looks pretty boring, you have to admin. But it’s in your full power to make it cooler. The next thing you want to achieve is to make whole thing a bit more explosive 💥, by scaling the rectangle out, as well as to make it fade out instead of fading in.

First things first, you add a new mixin, for scaling, called Scaling using handy [lerpDouble](https://api.flutter.dev/flutter/dart-ui/lerpDouble.html) from dart:ui.

mixin Scaling on Updatable {
  double from = 0; 
  double to = 1;
  double current;

  @override
  void update(Animation controller) {
    current = lerpDouble(from, to, controller.value);
  }
}

Next step is to have a Particle container for this behavior, which would apply the scaling to Canvas and pass control down the chain. Since it’s now quite clear that Particles are going to have a lot of… erm… children, you decide to express that behavior explicitly as well.

mixin NestedParticle on Particle {
  Particle child;

  @override
  void draw(Canvas canvas, Size size) {
    super.draw(canvas, size);
    child.draw(canvas, size);
  }

  @override
  void update(Animation controller) {
    super.update(controller);
    child.update(controller);
  }
}

You’re quite sure this thing will allow you to move your Particle factory to the next level.
Particle Systems (for Puffs and Zaps) with Flutter

One neat trick you’re going to use is that in Dart when composing an entity from multiple mixins, it’s still possible to utilise inherited behaviour via using super. The key to that is to be aware that mixins are sequential. So, if someone would ask you to illustrate it, you would show something like the following code.

mixin Loggable {
  log() {
    print('I am loggable!');
  }
}

mixin Loud on Loggable {
  log() {
    print('I am loud');
    super.log();
  }
}

mixin Clear on Loggable {
  log() {
    print('I am clear');
    super.log();
  }
}

// The order of declaration defines what would be "super"
// in each of the mixins above. Try swapping [Loud] and [Clear],
// or move loggable to be declared after [Loggable]
class LoudAndClear with Loggable, Loud, Clear {
  @override
  log() {
    super.log();
    print('Am i loud and clear?');
  }
}

main() {
  var loudAndClear = new LoudAndClear();
  loudAndClear.log();
}

So, with your current setup, if you have more than one mixin competing for base update and draw methods to implement their behavior, it’s just important to not forget to call super, just like you did in NestedParticle.

With that, implementing a ScalingParticle is a breeze.

class ScalingParticle extends Particle with Scaling, NestedParticle {
  double from;
  double to;
  Particle child;

  ScalingParticle({
    this.from = 0.0, 
    this.to = 1.0,
    @required this.child,
  });

  @override
  void draw(Canvas canvas, Size size) {
    canvas.save();
    canvas.scale(current);
    super.draw(canvas, size);
    canvas.restore();
  }
}

You like to think of this pattern as of cascade of control. The rule is just right-to-left, starting with whatever is written in original class method.
Particle Systems (for Puffs and Zaps) with Flutter
So, during draw phase, ScalingParticle will rescale a new canvas layer and then pass control to NestedParticle which will ensure that child draw is called.

During update phase, as ScalingParticle doesn’t implement any behavior for it, Scaling update will be called, which will set current to an expected scale as per AnimationController value.

You feel great that you don’t have to learn all of this from complete scratch, but if you would, you would refer to this beautiful article.
Particle Systems (for Puffs and Zaps) with Flutter

Next part is fading out instead of fading in. Luckily, it’s really easy in your layered system. So you just go to Fading and add a new enum, FadingDirection to represent possible variations of fading behavior, as well as change how update behaves, depending on the value of that enum.

enum FadingDirection { fadeIn, fadeOut }

mixin Fading on Updatable {
  FadingDirection direction = FadingDirection.fadeOut;
  double opacity;

  @override
  void update(Animation controller) {
    if (direction == FadingDirection.fadeOut) {
      opacity = (1 - controller.value);
    } else {
      opacity = controller.value;
    }
  }
}

Nothing stops you from utilizing the new behaviors now.
Particle Systems (for Puffs and Zaps) with Flutter

But that looks a bit… meh, so you change the Particles duration to be const Duration(milliseconds: 300). And parameterize the dimensions of FadingRect by adding a Size size field on that particle.

class FadingRect extends Particle with Fading {
  Size size;

  FadingRect({
    this.size = const Size(50, 50),
  });

  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawRect(
      Rect.fromCenter(center: Offset.zero, width: this.size.width, height: this.size.height),
      Paint()..color = Colors.white.withOpacity(opacity),
    );
  }
}

Now, it’s possible to set size of FadingRect to be something like FadingRect(size: Size(200, 200)). And the picture becomes a little bit more enjoyable, resembling a splash after you’re tapping the buttons.
Particle Systems (for Puffs and Zaps) with Flutter

A little bit less boring again. You feel that quite soon you’ll move to actually interesting stuff. To make yourself one step closer to “Puff”, you think that you need some way to implement a “burst” of Particle instances in all directions.

You decide that it’s time for a CompositeParticle.

The composition is a good neighbour of layers when it comes to building such systems as per your experience. It happens very often that if you need to operate on a single entity of certain type, you may want to operate over multiple entities too. Another important thing is the symmetry.

Particle Systems (for Puffs and Zaps) with Flutter

Symmetric things are more beautiful to your brain cause brain is never-stopping optimization machine trying to cut as many corners when it comes to computation as possible. No wonder it tries to do that, being responsible for a whopping 20% of your resting metabolic rate, more than any other organ in your body. Symmetry means a simpler way to understand things for your brain, which means less energy spent which makes your brain happy.

Particle Systems (for Puffs and Zaps) with Flutter

You don’t mind your brain being happy at all, so always try to look for ways to apply symmetry to your codebases, so that entities on different levels of your architecture would look and behave symmetrically to each other.

And today is no exception to that symmetry of yours. So, CompositeParticles is symmetrical to how you implemented the NestedParticle behaviour with addition to allowing to have as many (or little) children Particle as needed.

mixin CompositeParticle on Particle {
  List<Particle> children;

  @override
  void draw(Canvas canvas, Size size) {
    super.draw(canvas, size);

    for (var child in children) {
      child.draw(canvas, size);
    }
  }

  @override
  void update(Animation controller) {
    super.update(controller);
    
    for (var child in children) {
      child.update(controller);
    }
  }
}

With that, it’s quite easy to implement a Burst , a composite particle which just throws its nested children away in random directions while fading them, using all you already prepared.

/// Helpers for randomized dimensions
class Randoms {
  static final rnd = Random();

  /// Returns a random [Offset] from the "center" point of given size
  static Offset offsetFromSize(Size size) {
    return Offset(
      (rnd.nextDouble() * size.width) - (size.width / 2),
      (rnd.nextDouble() * size.height) - (size.height / 2),
    );
  }
}

/// [Burst] takes a list of children [Particle],
/// and wraps each one of them with [MovingParticle] in a random direction
/// from the center of the canvas, within specified [Size]
class Burst extends Particle with CompositeParticle {
  List<Particle> children;

  Burst({
    @required List<Particle> children,
    Size size = const Size(100, 100),
  }) {
    this.children = children
        .map<Particle>(
          (particle) => MovingParticle(
            from: Offset.zero,
            to: Randoms.offsetFromSize(size),
            child: particle,
          ),
        )
        .toList();
  }
}

And you simply use it in the OutlineButton.

// In OutlineButton.build
// ...
particle: Aligned(
  child: Burst(
    children: List<Particle>.generate(
      10,
      (i) => FadingRect(),
    ),
  ),
),
// ...

Particle Systems (for Puffs and Zaps) with Flutter

And the result… Would be considered good if it would be rated by Ghast. So you spend a bit of time adapting it for humans.

You simply swap FadingRect with FadingCircle , which is super easy to implement for you at this stage.

class FadingCircle extends Particle with Fading {
  final double radius;

  FadingCircle({
    this.radius,
  });

  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawCircle(
      Offset.zero,
      radius,
      Paint()..color = Colors.white.withOpacity(opacity),
    );
  }
}

The result looks ok. But you have plans to make it more interesting. First of all, to randomize FadingCircle radiuses, so it looks less repetitive.

// In OutlineButton.build > Particles > Aligned > FadingCircle
// ...
radius: Randoms.rnd.nextDouble() * 10
// ...

And next, is to add easing to the movement of circles in a Burst. Right now it simply linearly interpolates motion between 0 and 1. You this motion to be more organic and life-like.

To do so, in the Particles instead of passing the AnimationController directly to the children ParticlePainter, you decide to pass down the eased version of that Animation, which could be configured, defaulting to Curves.linear.

class Particles extends StatefulWidget {
  final Duration duration;
  final Particle particle;
  final ParticlesWidgetBuilder builder;
  
  // New property you defined to make animation
  // easing configurable from outside
  final Curve curve;

  const Particles({
    @required this.particle,
    @required this.builder,
    this.duration = const Duration(milliseconds: 400),
    
    // Default behavior remains as is - no easing
    this.curve = Curves.linear,
  });

  @override
  _ParticlesState createState() => _ParticlesState();
}

class _ParticlesState extends State<Particles>
    with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation animation;


  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: widget.duration,
    );
    
    // Initialize animation to be passed down to [ParticlePainter] instead
    // of original controller
    animation = CurvedAnimation(curve: widget.curve, parent: controller);
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, child) {
        return CustomPaint(
          child: child,
          painter: ParticlePainter(
            // Passing new curved animation here
            animation: animation,
            particle: widget.particle,
          ),
        );
      },
      child: widget.builder(context, controller),
    );
  }
}

When done, you simply pass Curves.easeOutQuint for that super fluid motion, as well as increase duration to const Duration(seconds: 1) when creating Particles in OutlineButton build. And voila, the prestige.
You decide to level up this game up a notch and spread their transition time start a bit. As in many other cases, there’s an awesome Flutter built-in available, just perfect for such a use: Interval.

As Interval is itself a Curve, you decide to go a slightly more generic route and, implement a behavior for using arbitrary Curve instances during Particle update cycle.

mixin Curved on Updatable {
  Curve curve;

  @override
  void update(Animation animation) {
    super.update(
      CurveTween(curve: curve).animate(animation),
    );
  }
}

And next, just implement another Particle, using this behavior, keeping the whole system in symmetry.

class CurvedParticle extends Particle with NestedParticle, Curved {
  Curve curve;
  Particle child;

  CurvedParticle({
    @required this.curve,
    @required this.child,
  });
}

And then, simply start using it in the Burst.

// in Burst constructor, children.map(...)
// ...
(particle) => CurvedParticle(
  curve: Interval(
    // Interval would start at random point from 0 to 0.5
    // and finish at random point between 0.6 and 1.0
    Randoms.rnd.nextDouble() * .5,
    Randoms.rnd.nextDouble() * .4 + .6,
  ),
  child: MovingParticle(
    from: Offset.zero,
    to: Randoms.offsetFromSize(size),
    child: particle,
  ),
),
// ...

Now it’s something you could even show to other people!
As another iteration, you add a bit of scaling to these FadingCircle, when creating them inside of OutlineButton.

// In OutlineButton.build > Particles > Aligned
// ...
child: Burst(
  children: List<Particle>.generate(
    20,
    (i) => ScalingParticle(
      child: FadingCircle(radius: Randoms.rnd.nextDouble() * 8 + 2),
      from: .2,
      to: 1.5,
    ),
  ),
),
// ...

After that, your effort goes ballistic and you start introducing additional helpers one right after another.

/// A function which returns [Particle] when called
typedef ParticleProvider = Particle Function(int i);

/// A [CompositeParticle] which allows to use [ParticleProvider] 
/// generator functions as source for children particles
/// 
/// ```dart
/// // 10 plain fading circles
/// ParticleGenerator(10, (i) => FadingCircle());
/// 
/// // 10 randomly sized fading circles
/// ParticleGenerator(10, (i) => FadingCircle(radius: Randoms.rnd.nextDouble() * 10));
/// 
/// // 5 small and 5 large fading circles
/// ParticleGenerator(10, (i) => FadingCircle(radius: i < 5 ? 10 : 20));
/// ```
class ParticleGenerator extends Particle with CompositeParticle {
  List<Particle> children;

  ParticleGenerator(
    int count,
    ParticleProvider generator,
  ) {
    this.children = List<Particle>.generate(count, generator);
  }
}

First of them is ParticleGenerator, allowing you to programmatically generate particles on the fly, a source of even greater variance in what could be achieved.

class FadingCircle extends Particle with Fading {
  final double radius;
  final Color color;

  FadingCircle({
    this.radius = 10,
    this.color = Colors.white,
  });

  @override
  void draw(Canvas canvas, Size size) {
    canvas.drawCircle(
      Offset.zero,
      radius,
      Paint()..color = color.withOpacity(opacity),
    );
  }
}

You also introduce a Circles particle, which draws… (wait for it, just while reading this text in parenthesis…) multiple circles on a Canvas at once, for more puffy shapes.

/// Just a container for parameters 
/// allowing to draw a circle on a [Canvas] later
class CircleParameters {
  double radius;
  Offset offset;

  CircleParameters({@required this.radius, @required this.offset});
}

/// Renders certain amount of circles on a [Canvas],
/// as per given [CircleParameters] list.
class Circles extends Particle with Fading {
  final List<CircleParameters> circles;

  /// Generates randomly positioned circles in
  /// given count with radius between given bounds.
  factory Circles.random({
    int count = 10,
    double maxRadius = 10,
    double minRadius,
  }) {
    if (minRadius == null) {
      minRadius = maxRadius * .1;
    }

    return Circles(
      circles: List<CircleParameters>.generate(
        count,
        (i) => CircleParameters(
          radius: Randoms.rnd.nextDouble() * maxRadius + minRadius,
          offset: Randoms.offsetFromSize(
            Size(maxRadius, maxRadius),
          ),
        ),
      ),
    );
  }

  Circles({this.circles});

  @override
  void draw(Canvas canvas, Size size) {
    for (var circle in circles) {
      canvas.drawCircle(
        circle.offset,
        circle.radius,
        Paint()..color = Colors.white.withOpacity(opacity),
      );
    }
  }
}

And then, just for ease of use in future, you enclose all the desired particles as one and call Puff ☁️☁️.

class Puff extends Particle with NestedParticle {
  Particle child;

  Puff() {
    // Will generate 50 nested particles
    this.child = ParticleGenerator(
      50,
      // Each of which would be positioned randomly
      // within enclosing canvas
      (i) => Aligned(
        alignment: Randoms.alignment(),
        // And with equal possibility would be either
        child: Randoms.rnd.nextDouble() > .5
            // Burst of large white circles flowing
            // slightly upwards
            ? CurvedParticle(
                curve: Interval(
                  .3,
                  1,
                ),
                child: Burst(
                  children: List<Particle>.generate(
                    2,
                    (_) => MovingParticle(
                      child: ScalingParticle(
                        child: Circles.random(count: 2, maxRadius: 50),
                      ),
                      from: Offset.zero,
                      to: Offset(0, -30),
                    ),
                  ),
                ),
              )
            // Or a circle appearing slightly lately
            // and not moving anywhere
            : CurvedParticle(
                curve: Interval(
                  Randoms.rnd.nextDouble() * .5 + .5,
                  1.0,
                  curve: Curves.fastOutSlowIn,
                ),
                child: ScalingParticle(
                  child: FadingCircle(
                    // Of either of two given colors
                    color: Randoms.rnd.nextDouble() > .5
                        ? Palette.accent
                        : Colors.purpleAccent,
                  ),
                ),
              ),
      ),
    );
  }
}

Dropping it to the OutlineButton is no effort at all.

// in OutlineButton.build > Particles
// ...
particle: Puff(),
// ...

And the Puff is live!
Despite you have done such systems multiple times in the past, you never get bored with creative freedom it allows you to reach.

You commit the code (full main.dart from the tutorial). You yawn. And you have that feeling of work well done which is one of the best rewards. Best rewards are given to you by your brain which literally gives you drugs to make you feel happier. But that’s another story and you decide that ⚡️ zaps ⚡️ will have to wait till you replenished your mental resource.

Your last thought right before Morpheus takes you is that you’re going to use Interval to make those za…

Thank you for reading this article!

#flutter #dart #mobile-app

What is GEEK

Buddha Community

Particle Systems (for Puffs and Zaps) with Flutter

Google's Flutter 1.20 stable announced with new features - Navoki

Flutter Google cross-platform UI framework has released a new version 1.20 stable.

Flutter is Google’s UI framework to make apps for Android, iOS, Web, Windows, Mac, Linux, and Fuchsia OS. Since the last 2 years, the flutter Framework has already achieved popularity among mobile developers to develop Android and iOS apps. In the last few releases, Flutter also added the support of making web applications and desktop applications.

Last month they introduced the support of the Linux desktop app that can be distributed through Canonical Snap Store(Snapcraft), this enables the developers to publish there Linux desktop app for their users and publish on Snap Store.  If you want to learn how to Publish Flutter Desktop app in Snap Store that here is the tutorial.

Flutter 1.20 Framework is built on Google’s made Dart programming language that is a cross-platform language providing native performance, new UI widgets, and other more features for the developer usage.

Here are the few key points of this release:

Performance improvements for Flutter and Dart

In this release, they have got multiple performance improvements in the Dart language itself. A new improvement is to reduce the app size in the release versions of the app. Another performance improvement is to reduce junk in the display of app animation by using the warm-up phase.

sksl_warm-up

If your app is junk information during the first run then the Skia Shading Language shader provides for pre-compilation as part of your app’s build. This can speed it up by more than 2x.

Added a better support of mouse cursors for web and desktop flutter app,. Now many widgets will show cursor on top of them or you can specify the type of supported cursor you want.

Autofill for mobile text fields

Autofill was already supported in native applications now its been added to the Flutter SDK. Now prefilled information stored by your OS can be used for autofill in the application. This feature will be available soon on the flutter web.

flutter_autofill

A new widget for interaction

InteractiveViewer is a new widget design for common interactions in your app like pan, zoom drag and drop for resizing the widget. Informations on this you can check more on this API documentation where you can try this widget on the DartPad. In this release, drag-drop has more features added like you can know precisely where the drop happened and get the position.

Updated Material Slider, RangeSlider, TimePicker, and DatePicker

In this new release, there are many pre-existing widgets that were updated to match the latest material guidelines, these updates include better interaction with Slider and RangeSliderDatePicker with support for date range and time picker with the new style.

flutter_DatePicker

New pubspec.yaml format

Other than these widget updates there is some update within the project also like in pubspec.yaml file format. If you are a flutter plugin publisher then your old pubspec.yaml  is no longer supported to publish a plugin as the older format does not specify for which platform plugin you are making. All existing plugin will continue to work with flutter apps but you should make a plugin update as soon as possible.

Preview of embedded Dart DevTools in Visual Studio Code

Visual Studio code flutter extension got an update in this release. You get a preview of new features where you can analyze that Dev tools in your coding workspace. Enable this feature in your vs code by _dart.previewEmbeddedDevTools_setting. Dart DevTools menu you can choose your favorite page embed on your code workspace.

Network tracking

The updated the Dev tools comes with the network page that enables network profiling. You can track the timings and other information like status and content type of your** network calls** within your app. You can also monitor gRPC traffic.

Generate type-safe platform channels for platform interop

Pigeon is a command-line tool that will generate types of safe platform channels without adding additional dependencies. With this instead of manually matching method strings on platform channel and serializing arguments, you can invoke native class and pass nonprimitive data objects by directly calling the Dartmethod.

There is still a long list of updates in the new version of Flutter 1.2 that we cannot cover in this blog. You can get more details you can visit the official site to know more. Also, you can subscribe to the Navoki newsletter to get updates on these features and upcoming new updates and lessons. In upcoming new versions, we might see more new features and improvements.

You can get more free Flutter tutorials you can follow these courses:

#dart #developers #flutter #app developed #dart devtools in visual studio code #firebase local emulator suite in flutter #flutter autofill #flutter date picker #flutter desktop linux app build and publish on snapcraft store #flutter pigeon #flutter range slider #flutter slider #flutter time picker #flutter tutorial #flutter widget #google flutter #linux #navoki #pubspec format #setup flutter desktop on windows

Terry  Tremblay

Terry Tremblay

1598396940

What is Flutter and why you should learn it?

Flutter is an open-source UI toolkit for mobile developers, so they can use it to build native-looking** Android and iOS** applications from the same code base for both platforms. Flutter is also working to make Flutter apps for Web, PWA (progressive Web-App) and Desktop platform (Windows,macOS,Linux).

flutter-mobile-desktop-web-embedded_min

Flutter was officially released in December 2018. Since then, it has gone a much stronger flutter community.

There has been much increase in flutter developers, flutter packages, youtube tutorials, blogs, flutter examples apps, official and private events, and more. Flutter is now on top software repos based and trending on GitHub.

Flutter meaning?

What is Flutter? this question comes to many new developer’s mind.

humming_bird_dart_flutter

Flutter means flying wings quickly, and lightly but obviously, this doesn’t apply in our SDK.

So Flutter was one of the companies that were acquired by **Google **for around $40 million. That company was based on providing gesture detection and recognition from a standard webcam. But later when the Flutter was going to release in alpha version for developer it’s name was Sky, but since Google already owned Flutter name, so they rename it to Flutter.

Where Flutter is used?

Flutter is used in many startup companies nowadays, and even some MNCs are also adopting Flutter as a mobile development framework. Many top famous companies are using their apps in Flutter. Some of them here are

Dream11

Dream11

NuBank

NuBank

Reflectly app

Reflectly app

Abbey Road Studios

Abbey Road Studios

and many more other apps. Mobile development companies also adopted Flutter as a service for their clients. Even I was one of them who developed flutter apps as a freelancer and later as an IT company for mobile apps.

Flutter as a service

#dart #flutter #uncategorized #flutter framework #flutter jobs #flutter language #flutter meaning #flutter meaning in hindi #google flutter #how does flutter work #what is flutter

Adobe XD plugin for Flutter with CodePen Tutorial

Recently Adobe XD releases a new version of the plugin that you can use to export designs directly into flutter widgets or screens. Yes, you read it right, now you can make and export your favorite design in Adobe XD and export all the design in the widget form or as a full-screen design, this can save you a lot of time required in designing.

What we will do?
I will make a simple design of a dialogue box with a card design with text over it as shown below. After you complete this exercise you can experiment with the UI. You can make your own components or import UI kits available with the Adobe XD.

#developers #flutter #adobe xd design export to flutter #adobe xd flutter code #adobe xd flutter code generator - plugin #adobe xd flutter plugin #adobe xd flutter plugin tutorial #adobe xd plugins #adobe xd to flutter #adobe xd tutorial #codepen for flutter.

Ruth  Nabimanya

Ruth Nabimanya

1620633584

System Databases in SQL Server

Introduction

In SSMS, we many of may noticed System Databases under the Database Folder. But how many of us knows its purpose?. In this article lets discuss about the System Databases in SQL Server.

System Database

Fig. 1 System Databases

There are five system databases, these databases are created while installing SQL Server.

  • Master
  • Model
  • MSDB
  • Tempdb
  • Resource
Master
  • This database contains all the System level Information in SQL Server. The Information in form of Meta data.
  • Because of this master database, we are able to access the SQL Server (On premise SQL Server)
Model
  • This database is used as a template for new databases.
  • Whenever a new database is created, initially a copy of model database is what created as new database.
MSDB
  • This database is where a service called SQL Server Agent stores its data.
  • SQL server Agent is in charge of automation, which includes entities such as jobs, schedules, and alerts.
TempDB
  • The Tempdb is where SQL Server stores temporary data such as work tables, sort space, row versioning information and etc.
  • User can create their own version of temporary tables and those are stored in Tempdb.
  • But this database is destroyed and recreated every time when we restart the instance of SQL Server.
Resource
  • The resource database is a hidden, read only database that holds the definitions of all system objects.
  • When we query system object in a database, they appear to reside in the sys schema of the local database, but in actually their definitions reside in the resource db.

#sql server #master system database #model system database #msdb system database #sql server system databases #ssms #system database #system databases in sql server #tempdb system database

Brain  Crist

Brain Crist

1602147600

Flutter App Development Trends 2020

As the new decade dawns upon us, a slew of technologies has been making a lot of noise to grab the developers’ attention. While native app development is going strong, the trade winds are now blowing towards going cross-platform.

Adobe PhoneGap, React Native, Xamarin and Ionic are all leaving no stone unturned to be the undefeated champion of cross-platform development. Still, Google’s Flutter is all set to take them all on at once.

There are a tonne of resources available online to learn about Flutter, and you can start with this step by step flutter guide.

With reduced code development time, increased time-to-market speed, near-native performance, and a bevy of advantages under its hood, Flutter is set to dominate the market this decade.

Before we take a look at trends making the Flutter race ahead in 2020, let us do a quick recap of what Flutter is, for those who have been living under a rock.

#flutter #flutter-for-mobile-app #flutter-app-development #mobile-app-development #flutter-trends #software-development #advantages-of-flutter-mobile #pros-and-cons-of-flutter