preface

Not long ago, I used the weekend to learn and complete a simple Flutter project — Simple Weather, simple but not simple, rich but not complex. This simple Flutter weather project provides real-time, multi-day, 24-hour, typhoon path, voice broadcast and life index services. Supports location, deletion, and search.

The following picture shows the homepage effect. Click Download to experience it:

The project uses a large number of custom drawing widgets, rich custom chart effect on the home page and cool weather background animation. The dynamic effects of weather background show different effects under different weather conditions. At present, a total of 15 categories have been realized, including sunny, sunny and late, cloudy, cloudy and late, overcast, small heavy rain, small heavy snow, fog, haze, floating dust and thunderstorm. Background dynamic effects are divided into three layers:

  • Background color layer. Gradient effect from top to bottom
  • The clouds. There is only one kind of picture, and different changes are made to its displacement, quantity and dyeing to achieve different effects
  • Information layer. Includes rain, snow, thunderstorm, and sun-up meteor effects

The implementation details of rain, snow and night meteor effect are described in two previous articles:

  • “Flutter- Draw” achieves cool rain and snow effects
  • “Flutter- Draw” achieves a dreamy meteor effect

Today we are going to cover the final background animation, how to achieve cool thunder and lightning effects, first take a look at the final results:

To prepare

According to the analysis of the implementation effect, the raindrop effect has been introduced in the previous article and will not be described in detail. After careful observation, it is actually to control the alpha of the lightning picture when drawing to create this thunderbolt effect.

First of all to prepare a few pieces of lightning material, UI website for a long time did not find satisfactory results, the key time and money. Later found that the latest version of Oppo weather thunderstorm effect is not cool, so decompile it, find his resource directory. In fact, the animation effect of opPO thunderstorm is realized by the way of video +openGL, which has static resources of lightning, video resources and openGL code files. We just need to extract his static resource file. Get the loaded image resource asynchronously in initState() :

  Future<void> fetchImages() async {
    weatherPrint("Start getting thunderstorm pictures");
    var image1 = await ImageUtils.getImage('assets/images/lightning/lightning0.webp');
    var image2 = await ImageUtils.getImage('assets/images/lightning/lightning1.webp');
    var image3 = await ImageUtils.getImage('assets/images/lightning/lightning2.webp');
    var image4 = await ImageUtils.getImage('assets/images/lightning/lightning3.webp');
    var image5 = await ImageUtils.getImage('assets/images/lightning/lightning4.webp');
    _images.add(image1);
    _images.add(image2);
    _images.add(image3);
    _images.add(image4);
    _images.add(image5);
    weatherPrint("Thunderstorm image obtained successfully:${_images? .length}");
  }
Copy the code

Once you have the image, start building the object and parameter list. According to the above analysis, in addition to the basic coordinate x and Y information, only additional alpha attribute is needed to achieve the effect.

class ThunderParams {
  ui.Image image;
  double x;
  double y;
  double alpha;
  int get imgWidth => image.width;
  int get imgHeight => image.height;

  ThunderParams(this.image);

  void reset() {
    x = Random().nextDouble() * 0.5.wp -  1 / 3 * imgWidth;
    y = Random().nextDouble() * 0.05.hp;
    alpha = 0; }}Copy the code

The reset() method is used to reinitialize parameter information when the current thunderstorm ends.

draw

Once the parameters are configured, drawing is simple. Once you have the picture and the location information and alpha information, you can call the relevant API of canvas for drawing.

  void drawThunder(ThunderParams params, Canvas canvas, Size size) {
    if (params == null || params.image == null) {
      return;
    }
    canvas.save();
    var identity = ColorFilter.matrix(<double> [1.0.0.0.0.0.1.0.0.0.0.0.1.0.0.0.0.0, params.alpha, 0,]); _paint.colorFilter = identity; canvas.drawImage(params.image, Offset(params.x, params.y), _paint); canvas.restore(); }Copy the code

Drawing to the screen looks something like this:

animation

One last step away from being cool is animation.

First, we treat a single lightning bolt as an animated object, disappearing, showing and showing again, implementing the animation, with alpha going from 0 to 1, and then back to 0. But you may find that they appear faster than they disappear. We can do this with the TweenSequence class.

TweenSequence is an animation sequence that supports configuration weights and the corresponding animation Tween. In this way, we can give alpha a lower weight for animating the interval [0,1] and a higher weight for animating the interval [1,0].

    var _animation = TweenSequence([
      TweenSequenceItem(
          tween: Tween(begin: 0.0, end: 1.0)
              .chain(CurveTween(curve: Curves.easeIn)),
          weight: 1),
      TweenSequenceItem(
          tween: Tween(begin: 1.0, end: 0.0)
              .chain(CurveTween(curve: Curves.easeIn)),
          weight: 3),]);Copy the code

After implementation, the effect is as follows:

Then, we use three random lightning bolts as a group, do a loop animation, control their sequence frame, complete the continuous & different & random deletion effect.

	_controller = AnimationController(duration: Duration(seconds: 1), vsync: this);
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controller.reset();
        Future.delayed(Duration(milliseconds: 10)).then((value) { initThunderParams(); _controller.forward(); }); }});var _animation = TweenSequence([
      TweenSequenceItem(
          tween: Tween(begin: 0.0, end: 1.0)
              .chain(CurveTween(curve: Curves.easeIn)),
          weight: 1),
      TweenSequenceItem(
          tween: Tween(begin: 1.0, end: 0.0)
              .chain(CurveTween(curve: Curves.easeIn)),
          weight: 3),
    ]).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(
        0.0.1.0,
        curve: Curves.ease,
      ),
    ));
Copy the code

After a lightning animation, add.animate() configuration via control

Interval(0.0, 0.3, curve: ease. ease,)Copy the code

Configures the start and end of the animation execution sequence frame and the interpolator.

Through listening in addStatusListener animation execution state, when the trigger AnimationStatus.com pleted random wait after a certain period of time, start all over again.

To this, a cool thunder and lightning special effect is completed, is not very simple, if you feel good, then consider the weather animation background plug-in for the need of small partners to use