How deep is flutter nested? Expand the function to understand

Time:2020-11-18

background

The deep nesting problem bothers many students who have just come into contact with flutter. It not only seems uncomfortable, but also greatly affects the coding experience.

The big guys will tell you that you shouldSplit your own nested code(Custom widget or extract build method)To reduce nesting levels. This is really an effective method. Is there any other way to reduce the nesting level.

Too deep nesting affects the visual appearance of the code

This code demonstrates what is called nested hell

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Demo'),),
      body: Container(
        child: Offstage(
          offstage: false,
          child: ListView(
            children: <Widget>[
              Container(
                color: Colors.white,
                padding: EdgeInsets.all(20),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Icon(Icons.phone),
                    Text("amy"),
                  ],
                ),
              ),
              Container(
                color: Colors.white,
                padding: EdgeInsets.all(20),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Icon(Icons.phone),
                    Text("billy"),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

After extracting the build method, the nesting level is obviously improved

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Demo'),),
      body: Container(
        child: Offstage(
          offstage: false,
          child: ListView(
            children: <Widget>[
              buildItem("amy"),
              buildItem("billy"),
            ],
          ),
        ),
      ),
    );
  }

  Container buildItem(String name) {
    return Container(
      color: Colors.white,
      padding: EdgeInsets.all(20),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Icon(Icons.phone),
          Text(name),
        ],
      ),
    );
  }
}

Can we continue to optimize?

Custom extension function

For example: I want to give the second of the following codeTextWidget plusmarginTop:10attribute

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      child: Column(
        children: <Widget>[
          Text('billy'),
          Text('say hello'), //add margin top??
        ],
      ),
    );
  }

At this time, I wish I could write:

How deep is flutter nested? Expand the function to understand

Obviously, flutter doesn’t support writing like this. Fortunately:Dart2.7 releaseOfficially announced support for extension methods

In fact, extension functions have been supported since dart 2.6.0
If pubspec.yaml If the dart version set in is lower than 2.6.0, a warning will appear

For example:
environment:
  sdk: ">=2.1.0 <3.0.0"

Warning:
Extension methods weren’t supported until version 2.6.0

First, define an extension function

extension WidgetExt on Widget {

  Container intoContainer({
      //Copy all parameters of container constructor (except child field)
    Key key,
    AlignmentGeometry alignment,
    EdgeInsetsGeometry padding,
    Color color,
    Decoration decoration,
    Decoration foregroundDecoration,
    double width,
    double height,
    BoxConstraints constraints,
    EdgeInsetsGeometry margin,
    Matrix4 transform,
  }) {
      //Call the constructor of the container and take the current widget object as the child parameter
    return Container(
      key: key,
      alignment: alignment,
      padding: padding,
      color: color,
      decoration: decoration,
      foregroundDecoration: foregroundDecoration,
      width: width,
      height: height,
      constraints: constraints,
      margin: margin,
      transform: transform,
      child: this,
    );
  }
}

Now, there is one more widget objectintoContainer(...)The extension function, and the parameter andContainerTherefore, we can write as follows:

How deep is flutter nested? Expand the function to understand

exceptContainerOther containers can be extended in the same way. As a result, the programming experience has been greatly improved, and it is no longer necessary to cut and paste large selection codes.

Chaining also supports:

Text("billy")
    .intoExpanded(flex: 1)
    .intoContainer(color: Colors.white)

Some widgets have multiple children. You can add the following extension functions:

extension WidgetExt on Widget {
  //Add an adjacent widget and return list < widget > to
  List<Widget> addNeighbor(Widget widget) {
    return <Widget>[this, widget];
  }

  //Add various single child widget containers
  //For example: container, padding, etc
}

extension WidgetListExt<T extends Widget> on List<T> {
  //Add an adjacent widget to the sublist < widget > list and return the current list
  List<Widget> addNeighbor(Widget widget) {
    return this..add(widget);
  }

  Row intoRow({
    Key key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline textBaseline,
  }) {
    return Row(
      key: key,
      mainAxisAlignment: mainAxisAlignment,
      mainAxisSize: mainAxisSize,
      crossAxisAlignment: crossAxisAlignment,
      textDirection: textDirection,
      verticalDirection: verticalDirection,
      textBaseline: textBaseline,
      children: this,
    );
  }
  //Add other multi child widget containers
  //For example: column, listview, etc
}

Using extension function to solve the problem of deep nesting

Back to this article’s original nested hell, our code can now be written like this

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('Demo'),),
        body: buildItem("amy")
              .addNeighbor(buildItem("billy"),)
              .intoListView()
              .intoOffstage(offstage: false)
              .intoContainer()
    );
  }

  Container buildItem(String name) {
    return Icon(Icons.phone)
        .addNeighbor(Text(name))
        .intoRow(crossAxisAlignment: CrossAxisAlignment.center,)
        .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),);
  }
}

Let’s define a more static code

class WidgetChain {
  static Widget addNeighbor(Widget widget) {
    return widget;
  }
}

In addition, a mapping extension method from data to widget is defined

extension ListExt<T> on List<T> {

  List<Widget> buildAllAsWidget(Widget Function(T) builder) {
    return this.map<Widget>((item) {
      return builder(item);
    }).toList();
  }

}

Now, the code looks like this:

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('Demo'),),
        body: ["amy", "billy"]
            .buildAllAsWidget((name) =>
              WidgetChain
              .addNeighbor(Icon(Icons.phone))
              .addNeighbor(Text(name))
              .intoRow(crossAxisAlignment: CrossAxisAlignment.center,)
              .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),)
            )
            .intoListView()
            .intoOffstage(offstage: false)
            .intoContainer()
    );
  }
}

It is worth noting that extension functions (no nesting) can be mixed with constructors (nested). The code above can be written like this(ContainerandOffstageThese 2 layers are changed to constructors:

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Demo'),),
      body: Container(
        child: Offstage(
          offstage: false,
          child: ["amy", "billy"]
            .buildAllAsWidget((name) =>
              WidgetChain
              .addNeighbor(Icon(Icons.phone))
              .addNeighbor(Text(name))
              .intoRow(crossAxisAlignment: CrossAxisAlignment.center,)
              .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),)
            )
            .intoListView()
        ),
      ),
    );
  }
}

Would you like to try this extension function? I have encapsulated the into extension functions corresponding to common widgets for you. You can eat them directly:

dependencies:
  widget_chain: ^0.1.0

Import:

import 'package:widget_chain/widget_chain.dart';

Then we can take off!

GitHub source code address:widget_chainStar Collection

summary

This paper introduces the nested hell in fluent, and uses the extension function to solve the nested hell problem.

Since extensive extension function calls will affect the code reading experience, it is still necessary to retain some key nested hierarchies to keep the hierarchical structure of the layout clear. The extension functions in this paper support mixed use with constructors, and the specific degree of use depends on your own choice


Author: Lucky Berry

Read the original

This article is the content of Alibaba cloud and can not be reproduced without permission.