[actual combat of fluent] six layout components and semicircle menu cases

Time:2021-10-27

[actual combat of fluent] six layout components and semicircle menu cases

Lao Meng’s introduction: the layout components in the shuttle include horizontal / vertical layout components(RowandColumn), overlay layout components(StackandIndexedStack), flow layout components(Wrap)And custom layout components(Flow)。

Horizontal and vertical layout components

RowIs a component that lays out sub components horizontally,ColumnIs a component that lays out subcomponents vertically. In the project90%All page layouts can be implemented through row and column.

Arrange the 3 components horizontally:

Row(
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

Arrange the 3 components vertically:

Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

There is a very important concept in row and column:Spindle (mainaxis)andCross axis, the spindle is the axis consistent with the component layout direction, and the cross axis is the axis perpendicular to the spindle direction.

For row components, the main axis is horizontal and the cross axis is vertical. Column is opposite to row. The main axis is vertical and the cross axis is horizontal.

Understand the concept of principal axis and cross axis, let’s take a lookmainAxisAlignmentProperty, which indicates the alignment of the spindle direction. The default value is start, which indicates the layout from the beginning of the component, where the start position andtextDirectionProperty. Textdirection represents the layout direction of the text. Its values include LTR (from left to right) and RTL (from right to left). When textdirection = ltr, start represents the left, and when textdirection = RTL, start represents the right,

Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    children: <Widget>[
      Container(
        height: 50,
        width: 100,
        color: Colors.red,
      ),
      Container(
        height: 50,
        width: 100,
        color: Colors.green,
      ),
      Container(
        height: 50,
        width: 100,
        color: Colors.blue,
      ),
    ],
  ),
)

[actual combat of fluent] six layout components and semicircle menu cases

The black border is the range of row control. By default, row is covered with parent components.

There are 6 spindle alignment methods, and the effect is shown in the following figure:

[actual combat of fluent] six layout components and semicircle menu cases

The difference between spacearound and spaceevery is:

  • spaceAround: the first child control is half the distance from the start and the last child control is half the distance from the other child controls.
  • spaceEvenly: all spacing is the same.

Corresponding to the spindle alignment is the cross axis alignmentcrossAxisAlignment, the cross axis alignment is centered by default. The height of the row control depends on the height of the child control. Therefore, when the height of the child control is the same, the height of the row and the height of the child control are the same. At this time, the cross axis alignment cannot be reflected. Modify the height of the three color blocks to 50100150 respectively, so that the height of the row is 150. The code is as follows:

Container(
      decoration: BoxDecoration(border: Border.all(color: Colors.black)),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            height: 50,
            width: 100,
            color: Colors.red,
          ),
          Container(
            height: 100,
            width: 100,
            color: Colors.green,
          ),
          Container(
            height: 150,
            width: 100,
            color: Colors.blue,
          ),
        ],
      ),
    )

[actual combat of fluent] six layout components and semicircle menu cases

The effect of spindle alignment is shown in the following figure:

[actual combat of fluent] six layout components and semicircle menu cases

mainAxisSizeIndicates the spindle size. There are two methods: min and max. the default is maxMin means as small as possible and Max means as large as possible.

Container(
    decoration: BoxDecoration(border: Border.all(color: Colors.black)),
    child: Row(
        mainAxisSize: MainAxisSize.min,
        ...
    )
)

[actual combat of fluent] six layout components and semicircle menu cases

Look at the black frame, which just wraps the sub components, and the max effect is as follows:

[actual combat of fluent] six layout components and semicircle menu cases

textDirectionIndicates the layout direction of the sub component spindle. The values include LTR (from left to right) and RTL (from right to left)

Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    textDirection: TextDirection.rtl,
    children: <Widget>[
      ...
    ],
  ),
)

[actual combat of fluent] six layout components and semicircle menu cases

verticalDirectionIndicates the cross axis layout direction of sub components:

  • up: start at the bottom and stack vertically to the top, with start at the bottom and end at the top.
  • down: opposite to up.
Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.start,
    verticalDirection: VerticalDirection.up,
    children: <Widget>[
      Container(
        height: 50,
        width: 100,
        color: Colors.red,
      ),
      Container(
        height: 100,
        width: 100,
        color: Colors.green,
      ),
      Container(
        height: 150,
        width: 100,
        color: Colors.blue,
      ),
    ],
  ),
)

[actual combat of fluent] six layout components and semicircle menu cases

Consider that this effect can be achieved by alignment, so whytextDirectionandverticalDirectionThese two attributes have been explained in the official API documents:

This is also used to disambiguate start and end values (e.g. [MainAxisAlignment.start] or [CrossAxisAlignment.end]).

Used to disambiguate the values of mainaxisalignment.start and crossaxisalignment.end.

Overlay layout component

The overlay layout component containsStackandIndexedStack, the stack component displays the sub components superimposed and stacked up according to the smooth of the sub components. The usage is as follows:

Stack(
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

The size of the stack pair of non positioned (not wrapped by positioned) subcomponents is determined by the fit parameter. The default value is stackfit.loose, which means that the subcomponents decide by themselves, and stackfit.expand means as large as possible. The usage is as follows:

Stack(
  fit: StackFit.expand,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

The effect is only yellow (the color of the last component). It is not that other components are not drawn, but that the other two components are covered by yellow components.

The alignment of the stack to the non positioned (not wrapped by the positioned) subcomponents is determined byalignmentControl. The upper left corner is aligned by default. The usage is as follows:

Stack(
  alignment: AlignmentDirectional.center,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

adoptPositionedPositioned sub components:

Stack(
  alignment: AlignmentDirectional.center,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Positioned(
      left: 30,
      right: 40,
      bottom: 50,
      top: 60,
      child: Container(
        color: Colors.yellow,
      ),
    )
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

topbottomleftrightFour positioning attributes represent the distance up, down, left and right.

If the subcomponent exceeds the stack boundary, theoverflowControl. The default is clipping. The following settings are always displayed:

Stack(
  overflow: Overflow.visible,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Positioned(
      left: 100,
      top: 100,
      height: 150,
      width: 150,
      child: Container(
        color: Colors.green,
      ),
    )
  ],
)

[actual combat of fluent] six layout components and semicircle menu cases

IndexedStackIs a subclass of stack. Stack displays all sub components superimposed, while indexedstack displays only the sub components of the specified index through index. The usage is as follows:

class IndexedStackDemo extends StatefulWidget {
  @override
  _IndexedStackDemoState createState() => _IndexedStackDemoState();
}

class _IndexedStackDemoState extends State<IndexedStackDemo> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(height: 50,),
        _buildIndexedStack(),
        SizedBox(height: 30,),
        _buildRow(),
      ],
    );
  }

  _buildIndexedStack() {
    return IndexedStack(
      index: _index,
      children: <Widget>[
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.red,
            alignment: Alignment.center,
            child: Icon(
              Icons.fastfood,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.green,
            alignment: Alignment.center,
            child: Icon(
              Icons.cake,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.yellow,
            alignment: Alignment.center,
            child: Icon(
              Icons.local_cafe,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
      ],
    );
  }

  _buildRow() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        IconButton(
          icon: Icon(Icons.fastfood),
          onPressed: () {
            setState(() {
              _index = 0;
            });
          },
        ),
        IconButton(
          icon: Icon(Icons.cake),
          onPressed: () {
            setState(() {
              _index = 1;
            });
          },
        ),
        IconButton(
          icon: Icon(Icons.local_cafe),
          onPressed: () {
            setState(() {
              _index = 2;
            });
          },
        ),
      ],
    );
  }
}

[actual combat of fluent] six layout components and semicircle menu cases

Flow layout component

WrapLayout the sub components horizontally or vertically, and when the space runs out, wrap will wrap automatically, that is, flow layout.

Create multiple child controls as child controls of wrap. The code is as follows:

Wrap(
  children: List.generate(10, (i) {
    double w = 50.0 + 10 * i;
    return Container(
      color: Colors.primaries[i],
      height: 50,
      width: w,
      child: Text('$i'),
    );
  }),
)

[actual combat of fluent] six layout components and semicircle menu cases

directionProperty controls the layout direction. The default direction is horizontal, and the setting direction is vertical. The code is as follows:

Wrap(
  direction: Axis.vertical,
  children: List.generate(4, (i) {
    double w = 50.0 + 10 * i;
    return Container(
      color: Colors.primaries[i],
      height: 50,
      width: w,
      child: Text('$i'),
    );
  }),
)

[actual combat of fluent] six layout components and semicircle menu cases

alignmentProperty controls the spindle alignment,crossAxisAlignmentProperty controls the cross axis alignment. The alignment only works on rows or columns with remaining space. For example, if the horizontal direction is just filled completely, the effect will be full regardless of the setting of the spindle alignment.

Note: the main axis is the axis consistent with the current component direction, and the cross axis is the axis perpendicular to the current component direction. If the layout direction of wrap is the horizontal axis.horizontal, the main axis is the horizontal direction. On the contrary, the layout direction is the vertical axis.vertical, and the main axis is the vertical direction.

Wrap(
    alignment: WrapAlignment.spaceBetween,
    ...
)

There are 6 spindle alignment methods, and the effect is shown in the following figure:

[actual combat of fluent] six layout components and semicircle menu cases

spaceAroundandspaceEvenlyThe difference is:

  • spaceAround: the first child control is half the distance from the start and the last child control is half the distance from the other child controls.
  • spaceEvenly: all spacing is the same.

Set the cross axis alignment code as follows:

Wrap(
    crossAxisAlignment: WrapCrossAlignment.center,
    ...
)

If the main axis direction of wrap is horizontal and the cross axis direction is vertical, if you want to see the effect of the cross axis alignment, you need to set the height of the sub control to be different. The code is as follows:

Wrap(
  spacing: 5,
  runSpacing: 3,
  crossAxisAlignment: WrapCrossAlignment.center,
  children: List.generate(10, (i) {
    double w = 50.0 + 10 * i;
    double h = 50.0 + 5 * i;
    return Container(
      color: Colors.primaries[i],
      height: h,
      alignment: Alignment.center,
      width: w,
      child: Text('$i'),
    );
  }),
)

[actual combat of fluent] six layout components and semicircle menu cases

runAlignmentAttribute controls the alignment of each line in the cross drawing direction of wrap. Next, look directly at the effect diagram corresponding to the method in runalignment 6,

[actual combat of fluent] six layout components and semicircle menu cases

runAlignmentandalignmentDifferences between:

  • alignment: is the alignment in the spindle direction, acting on each row.
  • runAlignment: is the alignment in which each row is regarded as a whole in the direction of the cross axis.

spacingandrunSpacingProperty controls the gap between the wrap main axis direction and cross axis direction sub controls. The code is as follows:

Wrap(
    spacing: 5,
    runSpacing: 2,
    ...
)

[actual combat of fluent] six layout components and semicircle menu cases

textDirectionProperty indicates the direction of the sub components in the wrap spindle direction. The value ranges are LTR (from left to right) and RTL (from right to left). The following code is from right to left:

Wrap(
    textDirection: TextDirection.rtl,
    ...
)

[actual combat of fluent] six layout components and semicircle menu cases

verticalDirectionProperty indicates the direction of the sub component in the cross axis direction of wrap. The value range is up and down. The setting code is as follows:

Wrap(
    verticalDirection: VerticalDirection.up,
    ...
)

[actual combat of fluent] six layout components and semicircle menu cases

Note: the component with text 0 is below.

Custom layout components

In most cases, it will not be usedFlowHowever, flow can adjust the position and size of sub components and draw various cool effects in combination with matrix4.

The flow component is optimized to operate the sub components using the transformation matrix, and the performance is very efficient.

The basic usage is as follows:

Flow(
  delegate: SimpleFlowDelegate(),
  children: List.generate(5, (index) {
    return Container(
      height: 100,
      color: Colors.primaries[index % Colors.primaries.length],
    );
  }),
)

delegateControl the position and size of sub components, which are defined as follows:

class SimpleFlowDelegate extends FlowDelegate {
  @override
  void paintChildren(FlowPaintingContext context) {
    for (int i = 0; i < context.childCount; ++i) {
      context.paintChild(i);
    }
  }

  @override
  bool shouldRepaint(SimpleFlowDelegate oldDelegate) {
    return false;
  }
}

Delegate to inheritFlowDelegate, rewritepaintChildrenandshouldRepaintFunction, the sub components are drawn directly above, and the effect is as follows:

[actual combat of fluent] six layout components and semicircle menu cases

You can only see one color, not just this one, but overlay. Similar to stack, let each component have a certain offset,SimpleFlowDelegateAmend as follows:

class SimpleFlowDelegate extends FlowDelegate {
  @override
  void paintChildren(FlowPaintingContext context) {
    for (int i = 0; i < context.childCount; ++i) {
      context.paintChild(i,transform: Matrix4.translationValues(0,i*30.0,0));
    }
  }

  @override
  bool shouldRepaint(SimpleFlowDelegate oldDelegate) {
    return false;
  }
}

[actual combat of fluent] six layout components and semicircle menu cases

Each sub component is offset 30 downward from the previous component.

Imitation Nuggets – my effect

The effects are as follows:

[actual combat of fluent] six layout components and semicircle menu cases

When you get a page, you must first split it. The above effect is split as follows:

[actual combat of fluent] six layout components and semicircle menu cases

It is generally divided into three parts, with horizontal layout, red area and circular head code as follows:

_buildCircleImg() {
  return Container(
    height: 60,
    width: 60,
    decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(image: AssetImage('assets/images/logo.png'))),
  );
}

The blue area code is as follows:

_buildCenter() {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      Text ('lao Meng fluent ', style: TextStyle (fontsize: 20),),
      Text('Flutter、Android', style: TextStyle(color: Colors.grey),)
    ],
  );
}

The green area is an icon with the following code:

Icon(Icons.arrow_forward_ios,color: Colors.grey,size: 14,),

Combine these three parts:

Container(
  color: Colors.grey.withOpacity(.5),
  alignment: Alignment.center,
  child: Container(
    height: 100,
    color: Colors.white,
    child: Row(
      children: <Widget>[
        SizedBox(
          width: 15,
        ),
        _buildCircleImg(),
        SizedBox(
          width: 25,
        ),
        Expanded(
          child: _buildCenter(),
        ),
        Icon(Icons.arrow_forward_ios,color: Colors.grey,size: 14,),
        SizedBox(
          width: 15,
        ),
      ],
    ),
  ),
)

The final effect is the effect picture we see at the beginning.

Expand / collapse menu horizontally

Use flow to realize the function of horizontal expansion / retraction menu. The code is as follows:

class DemoFlowPopMenu extends StatefulWidget {
  @override
  _DemoFlowPopMenuState createState() => _DemoFlowPopMenuState();
}

class _DemoFlowPopMenuState extends State<DemoFlowPopMenu>
    with SingleTickerProviderStateMixin {
  //Animation must be with this class
  AnimationController _ ctrlAnimationPopMenu; // Define variables for animation
  IconData lastTapped = Icons.notifications;
  final List<IconData> menuItems = <IconData>[
    //Menu icon
    Icons.home,
    Icons.new_releases,
    Icons.notifications,
    Icons.settings,
    Icons.menu,
  ];

  void _updateMenu(IconData icon) {
    if (icon != Icons.menu) {
      setState(() => lastTapped = icon);
    } else {
      _ctrlAnimationPopMenu.status == AnimationStatus.completed
          ? _ CTRL animationpopumenu. Reverse() // effects of expanding and collapsing
          : _ctrlAnimationPopMenu.forward();
    }
  }

  @override
  void initState() {
    super.initState();
    _ctrlAnimationPopMenu = AnimationController(
      //Animation variables must be initialized
      Duration: const duration (milliseconds: 250), // animation duration: 250 ms
      Vsync: this, // the role of singletickerproviderstatemixin
    );
  }

//Generate popmenu data
  Widget flowMenuItem(IconData icon) {
    final double buttonDiameter =
        MediaQuery.of(context).size.width * 2 / (menuItems.length * 3);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: RawMaterialButton(
        fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
        splashColor: Colors.amber[100],
        shape: CircleBorder(),
        constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
        onPressed: () {
          _updateMenu(icon);
        },
        child: Icon(icon, color: Colors.white, size: 30.0),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Flow(
        delegate: FlowMenuDelegate(animation: _ctrlAnimationPopMenu),
        children: menuItems
            .map<Widget>((IconData icon) => flowMenuItem(icon))
            .toList(),
      ),
    );
  }
}

FlowMenuDelegateIt is defined as follows:

class FlowMenuDelegate extends FlowDelegate {
  FlowMenuDelegate({this.animation}) : super(repaint: animation);
  final Animation<double> animation;

  @override
  void paintChildren(FlowPaintingContext context) {
    double x = 50.0; // Starting position
    double y = 50.0; // Expand horizontally, y constant
    for (int i = 0; i < context.childCount; ++i) {
      x = context.getChildSize(i).width * i * animation.value;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(x, y, 0),
      );
    }
  }

  @override
  bool shouldRepaint(FlowMenuDelegate oldDelegate) =>
      animation != oldDelegate.animation;
}

[actual combat of fluent] six layout components and semicircle menu cases

Semicircle menu expand / collapse

The code is as follows:

import 'dart:math';

import 'package:flutter/material.dart';

class DemoFlowMenu extends StatefulWidget {
  @override
  _DemoFlowMenuState createState() => _DemoFlowMenuState();
}

class _DemoFlowMenuState extends State<DemoFlowMenu>
    with TickerProviderStateMixin {
  //Animation needs this class to mix
  //Animation variables, as well as initialization and destruction
  AnimationController _ctrlAnimationCircle;

  @override
  void initState() {
    super.initState();
    _ctrlAnimationCircle = AnimationController(
        //Initialize animation variables
        lowerBound: 0,
        upperBound: 80,
        duration: Duration(milliseconds: 300),
        vsync: this);
    _ctrlAnimationCircle.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    _ ctrlAnimationCircle.dispose(); // Destroy variables and release resources
    super.dispose();
  }

  //Generate flow data
  List<Widget> _buildFlowChildren() {
    return List.generate(
        5,
        (index) => Container(
              child: Icon(
                index.isEven ? Icons.timer : Icons.ac_unit,
                color: Colors.primaries[index % Colors.primaries.length],
              ),
            ));
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned.fill(
          child: Flow(
            delegate: FlowAnimatedCircle(_ctrlAnimationCircle.value),
            children: _buildFlowChildren(),
          ),
        ),
        Positioned.fill(
          child: IconButton(
            icon: Icon(Icons.menu),
            onPressed: () {
              setState(() {
                //Click to move the animation forward or backward
                _ctrlAnimationCircle.status == AnimationStatus.completed
                    ? _ctrlAnimationCircle.reverse()
                    : _ctrlAnimationCircle.forward();
              });
            },
          ),
        ),
      ],
    );
  }
}

FlowAnimatedCircleThe code is as follows:

class FlowAnimatedCircle extends FlowDelegate {
  final double radius; // Bind the radius and let the circle move
  FlowAnimatedCircle(this.radius);

  @override
  void paintChildren(FlowPaintingContext context) {
    if (radius == 0) {
      return;
    }
    double x = 0; // Start (0,0) at the center of the parent component
    double y = 0;
    for (int i = 0; i < context.childCount; i++) {
      x = radius * cos(i * pi / (context.childCount - 1)); // The coordinates are derived mathematically
      y = radius * sin(i * pi / (context.childCount - 1)); // The coordinates are derived mathematically
      context.paintChild(i, transform: Matrix4.translationValues(x, -y, 0));
    }// use matrix to locate each sub component
  }

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

[actual combat of fluent] six layout components and semicircle menu cases

communication

Laomeng fluent blog address (330 controls usage):http://laomengit.com

Welcome to Flutter exchange group (WeChat: laomengit) and official account [Lao Meng Flutter]:

[actual combat of fluent] six layout components and semicircle menu cases [actual combat of fluent] six layout components and semicircle menu cases

Recommended Today

Swift advanced (XV) extension

The extension in swift is somewhat similar to the category in OC Extension can beenumeration、structural morphology、class、agreementAdd new features□ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc What extensions can’t do:□ original functions cannot be overwritten□ you cannot add storage attributes or add attribute observers to existing attributes□ cannot add parent […]