Full of spices today, guaranteed to be fresh and delicious ----2018-12-20

1: Write in front:

There are many implementations for each layout. I just choose what I think is the best layout

For very complex layouts, it is recommended to start with a rough draft, then simulate the color blocks, and finally write Expanded+ Flex where the control has white space (as I say below, Flex is the assembly of Row+Column)

2. Select a few pictures of the town building:


1. Entry-level Layout 1:

Title 1.


2. The train of thought

It is easy to see that the three blocks are arranged horizontally with the ends on the side, so the Row cannot escape, and the middle is easy to think of Expanded

In this way, the middle part is automatically sized, and there is a lot of white space, which basically won’t cause overflow. It is better adapted to different screens. After writing the three parts, use a Container to cover the inner margin.


3. The problem solving

var rowLine = Row( children: <Widget>[ Icon( Icons.extension, color: Colors.blue, ), Expanded( child: Padding( padding: Edgeinset.only (left: 20), child: Text(" friend microview ", style: TextStyle(fontSize: 18),)), Icon(icon.arrow_forward)],); var test1 = Container(color: Colors.white, padding: EdgeInsets.all(15), child: rowLine);Copy the code

2. Entry-level Layout 2:

[Spec] : Small package 1– Add test background color

Really want to joke: want to add a background color want to add a trouble dead… I’m just trying to, you know, encapsulate the method

bg(Widget w, [Color color]) {
  return Container(color: color ?? randomARGB(), child: w);
}
Color randomARGB(){
  Random random = new Random();
  int r = 30 + random.nextInt(200);
  int g = 30 + random.nextInt(200);
  int b = 30 + random.nextInt(200);
  int a = 50 + random.nextInt(200);
  return Color.fromARGB(a, r, g, b);
}
Copy the code

Title 1.


2. The train of thought

With the above guidelines in mind, the following should not be too difficult for you:

Three rows, a Column in the middle, basically the same pattern as above, so it should be easy to get there

Pause here to illustrate the axis of the Flex layout. For columns, the axis is vertical

Transverse alternating axis, the default is staggered shaft center, so the effect of presented above, we only need to gently: crossAxisAlignment: crossAxisAlignment. Start, just finished a prototype, small refinements of the rest


3. The problem solving

The style of writing text is really upset, let’s extract it

Var commonStyle = TextStyle(color: color. black, fontSize: 18); Var infoStyle = TextStyle(color: color (0xff999999), fontSize: 13);Copy the code
Var headImg = image. asset("images/icon_gql.jpg", width: 45, height: 45,); / / in the middle of the var center2 = information Column (mainAxisAlignment: mainAxisAlignment center, crossAxisAlignment: CrossAxisAlignment. Start, and the children: "Widget > [Text (" calm", style: "Ying Long" -- Zhang Feng took a trip to a small pool for two years, but washed the world a few idle dust. TextOverflow.ellipsis, style: infoStyle, textAlign: TextAlign.start, ) ], ); / / time + icon at the end of the var end2 = Column (mainAxisAlignment: mainAxisAlignment center, the children: < Widget > [Text (" 06:45 "style: infoStyle), Icon(Icons.visibility_off,size: 20,color: Color(0xff999999), ) ], ); Var rowLine2 = Row(children: <Widget>[Padding(child: headImg, Padding: edgeinset.all (5)), Expanded(child: Padding(padding: EdgeInsets.all(5), child: center2)), end2 ], ); Var test2 = Container(height: 70, color: colors. white, padding: edgeinset. all(5), child: rowLine2);Copy the code

3. New level layout 1

[Specifications] : Small package 2

Ok, I’m going to seal it again: it feels like adding the padding is a lot of nonsense, so let’s encapsulate it

Pd (Text(" creat "), l: 5) just left / / PDA (Text (" creator gods "), 5) / / above margins above add Pading: / / before -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the Padding (child: headImg3, Padding: EdgeInsets.all(5), ),Copy the code
pd(Widget w, {double l, double t, double r, double b}) { return Padding( child: w, padding: EdgeInsets.fromLTRB(l ?? 0, t ?? 0, r ?? 0, b ?? 0), ); } // All the padding-pda (Widget w, double a) {return padding-inset.all (a), child: w; } // Return padding-in (child: w, double v}) {return padding-in (child: w, double v}) EdgeInsets.fromLTRB(h ?? 0, v ?? 0, h ?? 0, v ?? 0), ); }Copy the code

1. Play the Nuggets

This is the homepage bar of Web Nuggets, which is my favorite style, now take a wave on the flutter


2. The analysis

With the experience of the first two, this style should not be too difficult for you. The blocks are as follows:

If you’re a beginner and you don’t know where to start, let’s draw a Container and put a color in it, so it’s going from zero to one, and then it’s going to be plus one. I like cards. So let’s wrap this in Card, three pieces at a glance


3. The problem solving

In case you don’t know how big a layout is, you can wrap it with the above bg function, as follows:

The background will help with your layout, and of course remove the background at the end

Var bigStyle = TextStyle(color: color.black, fontSize: 20, fontWeight: fontweight.bold); Var btnStyle = TextStyle(color: color (0xffFFFFFF), fontSize: 13); var btnStyle = TextStyle(color: color (0xffFFFFFF), fontSize: 13); / / / / / / / / / / / / / / / / / / / / / / / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test 3 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / the left head var headImg3 = Image.asset("images/icon_90.png", width: 50, height: 50,); / / in the middle of the var center3 = information Column (mainAxisAlignment: mainAxisAlignment center, crossAxisAlignment: CrossAxisAlignment. Start, and the children: "Widget > [Text (" packer fierce" jet, style: bigStyle), Row (children: < widgets > [Icon (the Icons next_week, size: 15), pd (Text (" | no creator gods "), l: 5)],), Row (children: <Widget>[Icon(Icons. Keyboard, size: 15), pd(Text(" there is a style on the other side of the sea I have never seen "), L: 5)],),],); / / var end3 = at the end of the Column (mainAxisAlignment: mainAxisAlignment spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: <Widget>[ Row(children: <Widget>[ Icon(Icons.language,size: 15,), Icon(Icons. Local_pharmacy, size: 15), Icon(Icons. Person_pin_circle, size: 15)],), bg(PDHV (Text(" edit ",style: btnStyle,), h: 10, v: 3), Colors.blueAccent), ], ); Var rowLine3 = Row(children: <Widget>[PDA (headImg3, 5), Expanded(child: PDA (center3,5)), PDA (end3, 10),],); var test3 = Card( child: Container( height: 95, color: Colors.white, padding: EdgeInsets.all(5), child: rowLine3));Copy the code

Iv. Novice Level Layout (2)

1. Make a question: still take nuggets to play

This is a little bit more complicated


1. 2. How do you do?

There’s a lot of ways you can block it, you can block it any way you like, you can see the rows, you can view it as columns, right

On the outside is a Column, head, body, tail. The body is a Row, the two lines of text are columns, and the head and tail are both rows


3. The problem solving

/ / / / / / / / / / / / / / / / / / / / / / / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test 4 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the var line1_4 = Row (children: <Widget>[image. asset("images/icon_90. PNG ", width: 20, height: 20), Expanded(child: pd(Text(" icon_90. PNG "), l: 5),), Text("Flutter/Dart", style: infoStyle,) ], ); var center_right = Column( mainAxisSize: MainAxisSize.min, children: <Widget>[Text(" 英 文 版 ", style: littelStyle, maxLines: 2,), pd(Text("1.2: elegant view: image fit mode --BoxFit1.3: elegant view: colorBlendMode --colorBlendMode", style: infoStyle, maxLines: 2,overflow: TextOverflow.ellipsis),t:5), ], ); Var center4 = Row(children: <Widget>[Expanded(child: pda(center_right, 5)), Image.asset("images/wy_300x200.jpg", width: 80,height: 80,fit: BoxFit.fitHeight) ], ); var end4 = Row( children: <Widget>[ Icon(Icons.grade,color: Colors.green,size: 20,), Text("1000W",style: infoStyle,), pd(Icon(Icons.tag_faces,color:Colors.lightBlueAccent, size: 20),l:15,r:5), Text("2000W",style: infoStyle), ], ); var item4 = Column(children: <Widget>[line1_4, Expanded(child: center4), end4]); var test4 = Card( child: Container( height: 160, color: Colors.white, padding: EdgeInsets.all(10), child: item4));Copy the code

So with these four, you can see that the big pieces are made up of small pieces, and little pieces always make it,

So don’t be afraid to encounter complex interface, piece by piece, and finally piece by piece, you can solve a few small examples so, good digestion


Five :ListView testing

Now that you have an entry, when do you not test the ListView?

Of course, it’s just static right now, so you can extract the fields you need, encapsulate them into functions and then dynamically get the data to populate the view (I’m going to put it on the last day, I’m going to say static page test here)


1.ListView.builder
Item 2 Item 4
Var test5 = listView. builder(itemCount: 30, itemBuilder: 30) (BuildContext context, int index) { return Column(children: <Widget>[test2,Divider(height:1)],); });Copy the code

2.ListView.separated

This is another separatorBuilder, which is of the same type as itemBuilder

I have inserted test2 under index=1 (left image), in the form of multiple entries… Of course, you can control how you want to play, such as insert one every two (right), note: insert items do not count in the total number

Var test6 = listView.separated (itemBuilder: (CTX, I) {return Column(children: <Widget>[test4],); }, separatorBuilder: (ctx, i) { return Column(children: <Widget>[i==1?test2:Container()], ); }, itemCount: 40); Var test6 = listView.separated (itemBuilder: (CTX, I) {return Column(children: <Widget>[test4],); }, separatorBuilder: (ctx, i) { return Column( children: <Widget>[(i+1 ) % 2== 0 ? test2 : Container()], ); }, itemCount: 40);Copy the code

Vi. Operation interaction:

The three elements of the Bit world: data (M), interface (V), interaction (C or P),

A project is white, is around these three turn, say who is more important is nonsense no data is empty shell specimen, no interaction is vegetative, no interface at that time daydreaming… The interaction with Flutter feels so weird… Maybe it’s the idea of all the widgets that drives it

1. Innate interactive gifted controls
Switch Slider Checkbox TextField SnackBar BottomNavigationBar OutlineButton FlatButton RaisedButton IconButton FloatingActionButton, etc...Copy the code

2. What if you don’t have innate talent? —GestureDetectorGive you an aura

Take a look at the source code: Ok, a lot

GestureDetector({Key Key, this.child, this.ontap,---- click ----Function()-- this.ontapdown,---- Press: Function(TapDownDetails details)-- this.ontapup,---- raise: Function(TapUpDetails Details)---- this.onTapCancel,---- Cancel (onTap cannot be triggered) : The Function () - this onDoubleTap, - double-click - void Function () - this. OnLongPress, - long-press - void Function () - OnLongPressUp,---- Hold down to release ----void Function()---- this. OnVerticalDragDown,---- drag vertically Press ----Function(DragDownDetails Details) - this. OnVerticalDragStart, -- -- vertical drag - Function (DragStartDetails details) - Enclosing onVerticalDragUpdate - vertical drag update - Function (DragUpdateDetails details) - OnVerticalDragEnd,---- Drag vertically to end ----Function(DragEndDetails Details)---- This onVerticalDragCancel, - vertical drag cancelled - Function () - this. OnHorizontalDragDown, enclosing onHorizontalDragStart, this.onHorizontalDragUpdate, this.onHorizontalDragEnd, this.onHorizontalDragCancel, this.onPanDown, this.onPanStart, this.onPanUpdate, this.onPanEnd, this.onPanCancel, this.onScaleStart, this.onScaleUpdate, this.onScaleEnd, this.behavior, this.excludeFromSemantics = falseCopy the code

3. Test 1:Four big war
3.1. Source tracking:
This.ontap,---- click ----Function()-- this.ontapDown,---- press: Function(TapDownDetails details)-- this.ontapup,---- lift: Function(TapUpDetails details) this. OnTapCancel,---- Function()---- ----> final GestureTapDownCallback onTapDown; ---->[source tracing :GestureTapDownCallback] typedef GestureTapDownCallback = void Function(TapDownDetails details); ----> class TapDownDetails {// Creates details for a [GestureTapDownCallback]./// /// The [globalPosition] argument must not be null. TapDownDetails({ this.globalPosition = Offset.zero }) : assert(globalPosition ! = null); ---->[原 文 trace :Offset] class Offset extends OffsetBase {/// Creates an Offset. The first argument sets [dx], Creates an Offset the horizontal component, /// and the second sets [dy], the vertical component. const Offset(double dx, double dy) : super(dx, dy); // All right...Copy the code

3.2 Test Code
var box = Container( width: 100, height: 100, color: Colors.lightBlueAccent, ); var ctrl_test = GestureDetector( child: box, onTap: () { print("onTap"); }, onTapDown: (d) { print("onPanDown" + d.globalPosition.toString()); }, onTapUp: (d) { print("onTapUp" + d.globalPosition.toString()); }, onTapCancel: () { print("onTapUp"); });Copy the code
I/ Flutter (27114): onPanDownOffset(205.5, 384.5) OnTapUpOffset (205.5, 384.5) I/flutter (27114): onTap visible coordinate is onTapCancel relative to the screen vertexCopy the code

4. Test 2: The Big Three

As the name suggests… Not much said

This onDoubleTap, - double-click - void Function () - this. OnLongPress, - long-press - void Function () - This onLongPressUp, - long press release - void Function () -Copy the code
var ctrl_test2 = GestureDetector(
    child: box,
    onDoubleTap: () {
      print("onDoubleTap");
    },
    onLongPress: () {
      print("onLongPress");
    },
    onLongPressUp: () {
      print("onLongPressUp");
    });
Copy the code

5. Test 3: Battlefield Ssangyong (give only one, the other analogy)
OnVerticalDragDown,---- Drag vertically press ----Function(DragDownDetails Details)---- Enclosing onVerticalDragStart - vertical drag - Function (DragStartDetails details) - Enclosing onVerticalDragUpdate - vertical drag update - Function (DragUpdateDetails details) - OnVerticalDragEnd,---- Drag vertically to end ----Function(DragEndDetails Details)---- Enclosing onVerticalDragCancel, - vertical drag cancelled - Function () -Copy the code
var ctrl_test3 = GestureDetector(
    child: box,
    onVerticalDragDown: (d) {
      print("onVerticalDragDown---" + d.globalPosition.toString());
    },
    onVerticalDragStart: (d) {
      print("onVerticalDragStart---" + d.globalPosition.toString());
    },
    onVerticalDragUpdate: (d) {
      print("onVerticalDragUpdate---" + d.globalPosition.toString());
    },

    onVerticalDragCancel: () {
      print("onVerticalDragCancel---");
    });
Copy the code
I/ Flutter (4994): onVerticalDragDown-- Offset(182.5, 384.8) OnVerticalDragStart --Offset(182.5, 384.8) I/flutter (4994): OnVerticalDragUpdate --Offset(182.5, 390.2) I/flutter (4994): OnVerticalDragUpdate --Offset(181.8, 402.2) I/flutter (4994): OnVerticalDragUpdate --Offset(180.8, 420.5) I/flutter (4994): onVerticalDragUpdate-- Offset(181.2, 443.5)Copy the code

Seven, interactive operation small case

1: Click to generate the ball

The CustomPaint size of the canvas is magically 0, causing GestureDetector to fail

GestureDetector covers all of them. After subtracting the offset, the drawing of the ball will not be analyzed. It is to collect the ball and draw it again

1.1 Ball data carrier class:
class Draw {
  double x;
  double y;
  Color color;
  Draw(this.x, this.y, this.color);
}
Copy the code

1.2: Prepare the Canvas

See part 2 for drawGrid (I prefer it if I don’t)

Class CanvasView extends CustomPainter {BuildContext Context; Paint mPaint; CanvasView(this.context) { mPaint = new Paint(); } @override void paint(Canvas canvas, Size size) { balls.forEach((ball) { drawBall(canvas, ball); }); var winSize = MediaQuery.of(context).size; drawGrid(canvas, winSize); } @override bool shouldRepaint(CustomPainter oldDelegate) { // TODO: implement shouldRepaint return true; } void drawBall(Canvas, Draw ball) {mPaint. Color = ball.color; canvas.drawCircle(Offset(ball.x, ball.y), 10, mPaint); }}Copy the code

1.3. Data change and Rendering (interaction)
var balls = []; Class CanvasPage extends StatefulWidget {CanvasPage({Key Key, this.title}) : super(Key: Key); final String title; @override _CanvasPageState createState() => _CanvasPageState(); } class _CanvasPageState extends State<CanvasPage> { @override Widget build(BuildContext context) { var appBar = AppBar( Title: Text(" zhang Feng Jiejieli "),); var barTopHeight = MediaQueryData.fromWindow(window).padding.top; print(barTopHeight); var scf = Scaffold( appBar: appBar, body: CustomPaint( painter: CanvasView(context), )); return GestureDetector( child: scf, onTapDown: (d) { var pos = d.globalPosition; balls.add(new Draw(pos.dx, pos.dy - appBar.preferredSize.height - barTopHeight, randomRGB())); print(balls.length); setState(() {}); }); }}Copy the code

2.onPanUpdatetest

Implementation is still very simple, onPanUpdate time dot on the line

onPanUpdate: (d) {
      var pos = d.globalPosition;
      balls.add(new Draw(pos.dx,
          pos.dy - appBar.preferredSize.height - barTopHeight, randomARGB()));
Copy the code

3. Draw lines

Ok, this is a bit tricky, but we tested onPanDown, onPanUpdate, onPanEnd

The canvas of the Flutter is used in a strange way. It is not possible to record the previous drawing

Class CanvasView extends CustomPainter {BuildContext Context; Paint mPaint; double _downX; double _downY; double _upX; double _upY; CanvasView(this.context, this._downX, this._downY, this._upX, this._upY) { mPaint = new Paint() .. strokeWidth = 10 .. strokeCap = StrokeCap.round; } @override void paint(Canvas canvas, Size size) { var winSize = MediaQuery.of(context).size; drawGrid(canvas, winSize); print("_downX:$_downX,_downY:$_downY"); canvas.drawLine(Offset(_downX, _downY), Offset(_upX, _upY), mPaint); } @override bool shouldRepaint(CustomPainter oldDelegate) { // TODO: implement shouldRepaint return true; }}Copy the code
class CanvasPage extends StatefulWidget { CanvasPage({Key key, this.title}) : super(key: key); final String title; @override _CanvasPageState createState() => _CanvasPageState(); } class _CanvasPageState extends State<CanvasPage> { var _downX; var _downY; var _upX; var _upY; @override Widget build(BuildContext context) {var appBar = appBar (title: Text(" "),); var barTopHeight = MediaQueryData.fromWindow(window).padding.top; var scf = Scaffold( appBar: appBar, body: CustomPaint( painter: CanvasView(context, _downX, _downY, _upX, _upY), )); return GestureDetector( child: scf, onPanDown: (d) { _downX = d.globalPosition.dx; _downY = d.globalPosition.dy - appBar.preferredSize.height - barTopHeight; }, onPanUpdate: (d) { _upX = d.globalPosition.dx; _upY = d.globalPosition.dy - appBar.preferredSize.height - barTopHeight; setState(() {}); }, onPanEnd: (d) {_downX = -10.0; _downY = 10.0; _upX = 10.0; _upY = 10.0; setState(() {}); }); }}Copy the code

Eight, about the jump

Jump mode 1: Addroutes
return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.lightBlue, ), home: new CanvasPage(), routes: <String, WidgetBuilder> { '/clock': (BuildContext context) => ClockPage(), },); Of (context).pushnamed ('/clock');Copy the code

Jump mode 2: Open the control directly
Navigator.push(context,MaterialPageRoute(builder: (bu) => ClockPage()));
Copy the code

Closing mode:
Navigator.pop(context);
Copy the code
The convenience of flutter is that the layout is the object, and how cool that is:
1. When writing XML on Android, if you want a part of a layout file, it's awkward: CV, delete and change, sometimes id contact is even more awkward. 2. Although Android XML is much more reusable than Java code layout simplicity, it still has limitations. 3. The flutter layout is an object, and you can record it with variables and take it whenever you want. 4. The Flex layout of the Flutter makes the layout very adaptable, although Android's constrained layout is fine, but a little more complexCopy the code

Well, that’s all for today


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1 – making 2018-12-20 Flutter day 5 — Layout instance + Operation interaction
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books I’m the nuggets Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support