Nonsense not to say, first on the effect of this to achieve.

Gif format is poor pixels, the actual effect is much more natural. This project is actually a similar effect after seeing the small bookkeeping application of The Flutter. One of the best features of the Flutter is the dynamic Gaussian blur effect on the main screen. However, the dynamic blur effect of the Flutter is not as natural and smooth as that of the Flutter. We can search for small pool accounting comparison, enter the text below.

knowledge

  1. How to capture Widget images of the current screen in Flutter.
  2. How Flutter applies gaussian blur to an image.
  3. How to fade-in and fade-out between two widgets.

The Flutter captures the Widget picture of the current screen

  1. There is no documentation on the website for this example, nor is there a method publicly available for the official Release of Flutter 3. However, there is documentation for capturing images of the current screen Widget in Flutter V0.4.4, which has not been publicly released.The address is here. We need to switch to the current development branch to see this new approachtoImage(). You can checkout of Flutter’s local git repository directlymasterBranching, of course, can also be done in the simpler way below. Run these two commands. The Flutter will automatically switch to the latest branch and download the dependencies.
flutter channel master
flutter doctor -v
Copy the code
  1. Wrap a Widget that needs a screenshotRepaintBoundary, the following sample code:
class _PngHomeState extends State<PngHome> {
  GlobalKey globalKey = new GlobalKey();

  // Take a screenshot of boundary and return the binary data of the image.
  Future<Uint8List> _capturePng() async {
    RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
    ui.Image image = await boundary.toImage();
    // Note: PNG is a compressed format. If you need raw pixel data for the image, use rawRgba
    ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    Uint8List pngBytes = byteData.buffer.asUint8List();
    return pngBytes;
  }

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      //globalKey is used for identification
      key: globalKey,
      child: Center(
        child: FlatButton(
          child: Text('Hello World', textDirection: TextDirection.ltr),
          onPressed: _capturePng,
        ),
      ),
    );
  }
Copy the code

Currently this method is quite time-consuming, it takes around 100ms to get a screenshot, not to mention we have to process the image, so although I cache the generated image, there is still a small pause (200-300ms) when I get the image for the first time.

Gaussian blur is applied to the resulting image

We have the binary data of the image, how do we gaussian blur it? A search of the official website found a great library: image. Add it to the project. Add the following code to pubspec.yaml:

"> < span style =" font-size: 14px; line-height: 20px;"^ 1.1.32"
Copy the code

Import an alias from the project that does not conflict with the existing Image library of Flutter:

import 'package:image/image.dart' as gimage;
Copy the code

Next, we can call the gaussianBlur() method in the library directly:

    // Continue with the above sample code
    RenderRepaintBoundary boundary =
        globalKey.currentContext.findRenderObject();
    ui.Image image = await boundary.toImage();
    // Must be converted to rawRgba, otherwise conversion is a waste of time
    var pixelsData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
    var pixels = pixelsData.buffer.asUint8List();
    var width = image.width;
    var height = image.height;
    // Get the IM object
    gimage.Image im = gimage.Image.fromBytes(width, height, pixels);
    // Gaussian blur (very slow)
    var gsImage = gimage.gaussianBlur(im, 10);
    // There is a problem here, you have to transcode gsImage to display it on screen, the Image widget does not support RGBA format.
    // Convert to JPG format
    var jpgImage = gimage.encodeJpg(gsImage, quality: 80);
Copy the code

You can imagine how slow the efficiency is, basically wait two or three seconds is normal, if you are not sensitive to time, this is not a big problem, but it is far from the dynamic blur I want the current interface effect. I searched Github and didn’t find a fast fuzzy algorithm that was implemented in Dart. This revealed a big problem with Flutter: its ecology is not yet established. Dart actually has very few open source projects on Github, but the language is JS, which is syntactically similar and interchangeable. I found the JS project StackBlur on Google and converted it directly into the Dart language format without any great difficulty. I will attach the Github warehouse address of this project later. If you need this algorithm, you can go to lib/widget/blur. Using the new algorithm is not enough, because the blur time is proportional to the size of the image, so it is best to scale the image and blur it again, the code is as follows:

    // Continue with the above sample code
    RenderRepaintBoundary boundary =
        globalKey.currentContext.findRenderObject(); 
    // Zoom first, take 0.5 times the original image size, reduce the blur time (about 60ms)
    ui.Image image = await boundary.toImage(pixelRatio: 0.5);
    // Convert to rawRgba format
    var pixelsData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
    var pixels = pixelsData.buffer.asUint8List();

    // Use the new algorithm to blur (50-60ms)
    processImageDataRGBA(pixels, 0.0, image.width, image.height, 4);
    
    // Turn pixels back to Image and encode it as JPG (around 200ms)
    gimage.Image newImage =
        new gimage.Image.fromBytes(image.width, image.height, pixels);
    List<int> jpgList = gimage.encodeJpg(newImage);
    return jpgList;
Copy the code

After these steps, the delay time can be controlled within 400ms, although it can not be completely free, at least the waiting time is barely acceptable. Some of you may have noticed that coding to JPG takes a lot of time. I have no good idea about this (I’m still working on it) because the Image widget of Flutter only supports displaying encoded images, such as JPG, PNG, WebP, Gif, etc. But you can’t display raw pixel images, so you have to encode the processed images as JPG. (Why only toByteData() without fromByteData()? Who knows what the developers of Flutter think, there may be an API for Flutter in the future.

How to fade-in and fade-out between two widgets.

Currently we have two widgets, one is the original interface, and the other is an ImageWidget with a screenshot of the original interface and a blurred image. To achieve the gradient switching effect of the initial Gif image, we need to use a new control: AnimatedCrossFade, which has very simple effects: If you have two widgets, the first one fades out and the second one fades in to achieve a smooth effect, which is also achieved by the two fadetransitionWidgets. How to use it is simple:

 new AnimatedCrossFade(
   duration: const Duration(seconds: 3),
   firstChild: const FlutterLogo(style: FlutterLogoStyle.horizontal, size: 100.0),
   secondChild: const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
   crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
 )
Copy the code

The above code is an example of changing the FlutterLogo, simply changing the value of _first in setState() to display FirstChild or SecondChild. Complete interface code can refer to the source code, here is no longer released.

The attached:

Chic_Github

feeling

Flutter, one of Google’s latest initiatives, is getting a lot of attention because it aims to change the problem of the current two-in-one, two-implementation mobile APP. I dare not comment on the future prospects of this technology, but after a period of use, I have a little experience, recorded for readers’ reference:

  1. light

    There are no Gradle versions, no Android studios, and you don’t even have to manage Android versions. Select your favorite editor (VSCode, AS, IDEA) and build the Flutter projectmain.dartThe inside is dry. Anyone who’s worked on Android knows how annoying these release issues can sometimes be, and that’s one of the first things you know when you get a project that doesn’t work. From this point of view, Flutter is a big plus for my development experience. Not to mention drastically reducing wait timeshot reloadSuch features. In a word, relaxed and happy is my first feeling of Flutter learning.
  2. all

    If it is a framework’s duty to get developers to focus on business logic development as quickly as possible, then robust documentation and annotations are a bonus of Flutter. Apart from the detailed documentation and video tutorials on the website, the comments in the code are detailed enough. Here’s a quick example: If you want to customize oneViewGroupIn Android, you can inheritViewGroupthenmeasure.layout.drawThree steps. In Flutter, there’s nothing in the documentation about how to customize the one you wantViewGroup. So you want to gnaw the source code to see how the official implementation, take the simplestStackThe Widget’s comment says:
 /// If you want to lay a number of children out in a particular pattern, or if
 /// you want to make a custom layout manager, you probably want to use
 /// [CustomMultiChildLayout] instead. 
Copy the code
  • So you click inCustomMultiChildLayoutCheck it out and find this thisCustomMultiChildLayoutClass comments are not code comments, but tutorials hidden in comments.
/// ## Sample code./// // Define your own slot numbers, depending upon the id assigned by LayoutId.
/// // Typical usage is to define an enum like the one below, and use those
/// // values as the ids.
/// enum _Slot {
/// leader,
/// follower,
/ / /}
/// 
/// class FollowTheLeader extends MultiChildLayoutDelegate {
/// @override
/// void performLayout(Size size) {
/// Size leaderSize = Size.zero;
/// 
/// if (hasChild(_Slot.leader)) {
/// leaderSize = layoutChild(_Slot.leader, new BoxConstraints.loose(size));
/// positionChild(_Slot.leader, Offset.zero);
/ / /}
/// .Copy the code
  • I’m just going to throw you a bunch of sample code, and a bunch of details that I’m not going to cut out. What I want to say is that such examples are not special in Flutter, a lot of themWidgetWill be in the commentsThe sample codeInstead of switching to documentation or searching for answers, the code’s own comments solve a large part of the problem. From these detailed notes, we can also see how much Attention Google attaches to Flutter.
  1. steady

    Tell the truth from installationflutterUntil one runsHelloWorldIt didn’t take me long. Flutter is Dart language, Android, iOS, and AndroidStudio plugin. While the Flutter was downloading, I admit that I spent more than 10 seconds thinking about my computerAndroidStudio3Which path is installed in the end, leng did not remember. I didn’t thinkflutter doctor -vUpon running, a test report comes out: Flutter installation OK; Dart installation OK; You have AndroidSDK 27.0.3 installed on your computer. VSCode is there, no Flutter plugin installed; AndroidStudio is installed there with the Flutter plugin… Suddenly there is a kind of liberation of productivity moved, finally do not need to configure this Path that Path (say you JAVA), finally do not need to copy a string of Path names to copy to copy. This is the programming tool from the future, getting everything done and reporting back, not putting your memory to the test. At this point, Flutter deserves this stability.

Of course, there are still many problems with Flutter development. The biggest problem is that the ecosystem surrounding Flutter has not yet been developed. Flutter does not even have a proper ORM framework. Many operations must be done by writing SQL statements yourself. I’ll share a blog post about sqflite later. There should still be a long way to go until all the functions of the fake koji bookkeeping APP can be completed in my spare time. In the same way, the protagonist of this article —-Flutter still has a long way to go.

The 5.31 update

The preceding method is applicable only to one image. If you want to blur the widgets on the interface, use the BackdropFilter provided by the system. Using the fuzzy algorithm provided by Skia, it can bring faster and more resource-saving fuzzy effect.

BackdropFilterMethod of use

new BackdropFilter( filter: new ui.ImageFilter.blur(sigmaX: _sigma, sigmaY: _sigma), child: new Container( color: Color.blue. WithOpacity (_opacity), padding: const EdgeInsets. All (30.0), width: 90.0, height: 90.0, child: new Center( child: _showText ? new Text('Test') : null,
        ),
      ),
    );
Copy the code

Note how BackdropFilter draws the filter region. It first determines the region to filter according to the size of the internal child, then draws the effects provided by the filter (such as blur) to the background, and then draws the Child. If you look directly at the code above, you can see it in action (the blue areas are the fuzzy areas) :

You can see that Test is not blurred, but the background below the blue area has been blurred. You can adjust the level of blur by Sigma.

BackdropFilter can only handle rectangular areas. When you change blue areas to circles (using ClipOval), the blur effect will no longer work. This is a BUG with the Skia engine that has not been solved yet. Flutter BackdropFilter can’t handle non-rectangular clipping and text causes blur to bleed outside bounds

If you want to run the blurry example above, visit the original version or download a copy of it by linking below.

BackdropFilterFuzzy sample