Students who want to pit flutter are worried about nested hell. However, I have been using Flutter for almost a month and found that if flutter is used properly, nested hell can be avoided. I summarize 5 methods.

Method 1: Appropriate use of “higher-order components”

Flutter official document without the concept of “high order component”, I said here “high order component” refers to the basic components of the built-in components, if pure use basic components to build the UI, the nesting level will be a lot of, we should understand the built-in all kinds of “high order component”, and don’t be afraid of “high order component” inflexible, want to know, The child, title, leading, and other attributes of a component can be assigned to any other component, and “higher-order components” can be extended as well.

Example 1: Use ListTile instead of Row+Container

ListTile is a three-column layout component. If you need a three-column or two-column layout with a fixed width at both ends and an adaptive width in the middle, you can use it directly instead of using Row+Flex+Container.

return ListTile(
    leading: CircleAvatar(
      // Avatar radius
      radius: 25.NetworkImage, AssetImage project bundle, FileImage Locally stored images
      backgroundImage: NetworkImage('${mModel.headurl}'),
    ),
    title: Text(
      '${mModel.nick}',
      style: TextStyle(letterSpacing: 0, color: Colors.black, fontSize: 14),
    ),
    subtitle: Text(
      '${mModel.decs}',
      style: TextStyle(
          letterSpacing: 0, color: Color(0xff666666), fontSize: 10),
    ),
    trailing: mFollowBtnWidget(mModel, i - 1));Copy the code

Example 2: Use RichText instead of Text

import '.. /constant.dart';
RichText(
    text: TextSpan(
      text: 'Here's the title.',
      style: Constant.SUB_TITLE
      children: <TextSpan>[
        TextSpan(
            text: 'Here's the link',
            style: Constant.LINK,
        TextSpan(
            text: 'Fade here',
            style: Constant.MUTE_TEXT,
      ],
    ),
  )
Copy the code

Example 3: Use SliverAppBar instead of AppBar

SliverAppBar is an AppBar with a banner at the top and the banner can slide up and down. If you implement something like this yourself, you have to write a lot of nested and scrolling events. How to use it can be seen in the official documentation.

In short, corresponding to the official component, we should understand thoroughly, do not write a long time of code, the original is the official implementation of the component, waste of time not to say, but also increase the nesting level.

Method 2: Encapsulate custom components

Encapsulation is available in most languages and frameworks, and as you all know, there are a few things to note here:

Components suitable for encapsulation:

  • At the top of the AppBar
  • Thumb up button
  • Share button and share button group (such as wechat share, QQ share)
  • The person’s image
  • Common home buttons, default buttons (similar to buttons in vUE’s Vant component library)
  • Loading animation
  • Dialog dialogue window
  • Commonly used text with color and size attributes

Use global constants appropriately:

// file: constant.dart
class Constant {
  static const COLOR_TITLE = Color(0xFF202020);
  static const COLOR_SUBTITLE = Color(0xFF88888A);
  static const COLOR_MUTE = Color(0xccccccff);
  static const COLOR_WARN = Color(0xFFF59A23);
  static const COLOR_ERROR = Color(0xFFFA3651);
  static const COLOR_PRIMARY = Color(0xFFA33028);
  static const COLOR_LINK = Color(0xCC61ADF3);
  
  static const MAIN_TITLE = TextStyle(fontSize: 16, color: COLOR_TITLE);
  static const SUB_TITLE = TextStyle(fontSize: 12, color: COLOR_SUBTITLE);
  static const LINK = TextStyle(fontSize: 13, color: COLOR_LINK);
}
Copy the code

Use:

import '.. /constant.dart'; . Container( margin: EdgeInsets.only(top:3),
    child: Text(
        mCneterItem[0].hotdiscuss,
        style: Constant.LINK,
  )
Copy the code

Method 3: Use SizedBox instead of Container’s Margin and Spacer instead of Flex

If we use Container only to use its margin property, we can use SizedBox and Spacer instead. Such as:

Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        SizedBox(height: 5), Input( ... ) , SizedBox(height:5), Input( ... ) ,),,)Copy the code

Spacer simply wraps a Expanded SizedBox. It gives us flexibility to control Row/Column

body: Center(
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: <Widget>[
      Container(
        color: Colors.blue,
        margin: EdgeInsets.symmetric(horizontal: 5),
        height: 50,
        width: 50,
      ),
      Spacer(flex: 2), // The elastic coefficient is 2
      Container(
        color: Colors.blue,
        height: 50,
        margin: EdgeInsets.symmetric(horizontal: 5),
        width: 50,
      ),
      Spacer(), // The elastic coefficient defaults to 1
      Container(
        color: Colors.blue,
        margin: EdgeInsets.symmetric(horizontal: 5),
        height: 50,
        width: 50[], (), (Copy the code

4. Use Map instead of if else

Sometimes we use if else to return different component nesting, but only part of it is different. We can use Map or ternary syntax to return a variable, and we can use variables directly inside the component nesting. Example:

// Code before optimization:
if(level == 'level1') {
   return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage('https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg'),
            fit: BoxFit.cover,
          )),
    )
 } else {
   return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage('https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic2.jpg'),
            fit: BoxFit.cover,
          )),
    )
 }
// Optimized code
urls = {
'level1': 'https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg'.'level2': 'https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg'
}
return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage(urls[level]),
            fit: BoxFit.cover,
          )),
    ),
Copy the code

You might think you wouldn’t write code that crappy before optimization, but I see it all the time on Github, either because you’re lazy or because you don’t pay attention. At this point, review your code to see if it can be optimized.

Method 5: Use extension functions

This article is very good about extension functions: Flutter nested hell! This method is the ultimate solution to the nesting hell, but use it properly and don’t overuse it, otherwise it will affect your code reading. It is recommended to mainly use extension functions for style components such as color, size, paddig, visible, center, right, ClipOval, BorderRadius, etc. The author of the article also wrote an extension function library for us to use, which covers the commonly used extension functions, we can add their favorite extension functions on his basis.

Conclusion:

With the above 5 methods, I feel flutter smells good! Mom doesn’t have to worry about my nested hell problem anymore! Of course, each of these methods has its own scenarios and should be used in combination. Also, we need to learn how to refactor and remove duplicate code during development. Methods two and four actually remove duplicate code, thus avoiding nesting.