[TOC]
Build layouts in Flutter, mainly to explain the ideas and pitfalls encountered here.
Introduction to the Flutter layout mechanism
Widgets are at the heart of the Flutter layout mechanism. Almost everything in Flutter is a widget — even the layout model is a widget. Images, ICONS, and text seen in the Flutter app are widgets. Even things that you can’t see are widgets, such as rows, columns, and grids that arrange, constrain, and align these visible widgets.
The page to be laid out
According to the documentation, what we want to achieve is the effect of the following page, dividing the widget into four numerically arranged sub-widgets, each of which can be individually designed. The top down view is as follows: an image resource widget, a title widget, a button widget, and a text widget. Here the concept is clear, and each sub-layout is treated as a widget. We’ll take them down one by one.
How to load Image resources in Flutter (Part 1)
To be more specific, only image resources are loaded here. For other resources, see Resources and Images
- Add the image to the project directory, create a folder “images” under the project root, and place the image in it (note that wget cannot save this binary).
- Update the pubspec.yaml file to include assets tags. This will make your images available in your code. The update method is as follows:
- Pay attention to the location of the reference, do not write wrong, otherwise it will report the resource reference error
- Method of reference:
Body: new ListView(children: [new image.asset ('images/lake.jpg', height: 240.0, fit: boxfit.cover,), //... .)Copy the code
At this point, we have solved the picture problem.
Title Bar Widget Design (Part 2)
First, build the left column of the title section. Placing a Column in Expanded stretches the Column to use any free space left in the row. Set the crossAxisAlignment property to crossAxisAlignment. Start, which will left-align the children in the column. Put the first line of text into the Container, then add an 8-pixel fill at the bottom. The second subitem in the column (also text) is grayed out. The last two items in the title line are a red star icon and the word “41”. Place the entire row in the container and fill 32 pixels along each edge
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { Widget titleSection = new Container(padding: const EdgeInsets. All (32.0), child: New Row(children: [New Expanded(child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Container( padding: Const EdgeInsets. Only (bottom: 8.0), Child: new Text('Oeschinen Lake Campground', style: new TextStyle(fontWeight: FontWeight.bold, ), ), ), new Text( 'Kandersteg, Switzerland', style: new TextStyle( color: Colors.grey[500], ), ), ], ), ), new Icon( Icons.star, color: Colors.red[500], ), new Text('41'), ], ), ); / /... }Copy the code
Code parsing:
Design of Button Layout Widgets (Part 3)
The button section contains three columns that use the same layout – one icon above, one line of text below. The columns in this row are divided evenly over the row space, and the text and icon colors are the primary color in the theme, which is set to blue in the build() method of the application:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//...
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
//...
}
Copy the code
> Since the three buttons have the same layout and size, we use nested functions here, such as buildButtonColumn, which creates a Widget column with a primary color and an Icon and Text.
Column buildButtonColumn(IconData icon, String label) { Color color = Theme.of(context).primaryColor; return new Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [New Icon(Icon, color: color), new Container(margin: const EdgeInsets. Only (top: 8.0), child: new Text(label, style: New TextStyle(fontSize: 12.0, fontWeight: fontweight.w400, color: color,),),],); }Copy the code
The builder function adds the icon directly to the Column. Place the text in the container to add padding above the text, separating it from the icon. Build these columns by calling the function and passing the icon and text. And in the direction of the spindle through MainAxisAlignment spaceEvenly row space occupied the average distribution of each column.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //... Widget buttonSection = new Container( child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ buildButtonColumn(Icons.call, 'CALL'), buildButtonColumn(Icons.near_me, 'ROUTE'), buildButtonColumn(Icons.share, 'SHARE'), ], ), ); / /... }Copy the code
The text part
Put the text into the container to add a 32-pixel fill along each edge. The Softwrap attribute indicates whether text should be broken between soft newlines, such as periods or commas
Widget textSection = new Container(padding: const EdgeInsets. All (32.0), child: New Text(" "Lake Oeschinen lies at the foot of the Bluemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run. ''', softWrap: true, ), );Copy the code
integration
Put all of this together. These widgets are placed in the ListView, not the column, because the ListView scrolls automatically when the application runs on the small device.
Body: new ListView(children: [new image. asset('images/lake.jpg', width: 600.0, height: 240.0, fit: BoxFit.cover, ), titleSection, buttonSection, textSection, ], ),Copy the code
In this step, we can see that there is only one UI layout that we are dealing with, and that is the widget. We are just following the basic layout and simple nesting of images and text in the official demo, and refer to the Widget directory for more information on widgets
All layout is done in a widget, including methods. Dart’s structure looks like this: debugPaintSizeEnabled = true; // Enable visual debugging
void main() { debugPaintSizeEnabled = true; runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Widget titleSection = Container(padding: const EdgeInsets. All (32.0), Child: Row(children: [Expanded(Child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [),); Column buildButtonColumn(IconData icon, String label) {// custom method, } Widget buttonSection = Container(// here is the button Widget child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ buildButtonColumn(Icons.call, 'CALL'), buildButtonColumn(Icons.near_me, 'ROUTE'), buildButtonColumn(Icons.share, TextSection = Container(// here is the text Widget); return MaterialApp(title: 'Flutter Demo', home: Scaffold( appBar: AppBar( title: Text('Top Lakes'), ), body: ListView( children: [//1, image. asset('images/lake.jpg', width: 600.0, height: 240.0, fit: Box fit.cover,), //2, titleSection, //3, buttonSection, //4, textSection,],),);}}Copy the code
A layout widget with a single child element
Container
A widget with drawing, positioning, and resizing.
Container(
child: Container(
margin: const EdgeInsets.all(10.0),
color: const Color(0xFF00FF00),
width: 48.0,
height: 48.0,
),
Copy the code
Padding
A widget that adds the specified padding to its child widgets
// When you pass layout constraints to its children, the population shrinks the constraints for the given population, causing the children to layout at a smaller size. // Fill then adjusts its size to the size of its child, expanding through the fill, effectively creating empty space around the child. Padding(Padding: EdgeInsets. All (8.0), child: const Card(child: Text('hello world', style: TextStyle)) 18.0,),),),)Copy the code
Center
A widget that centers its child widgets within itself
Center(child: Container(height: 100.0, width: 100.0, color: Colors. Yellow), which aligns its child widgets and automatically resizes them based on their size. Child: Align(0.2, 0.6), child: Container(height: 40.0, width: 40.0, color: Colors.red, ), ), ), )Copy the code
Align
A widget that aligns and automatically resizes its child widgets based on their size.
Child: Align(0.2, 0.6), child: Container(height: 40.0, width: 40.0, color: Colors.red, ), ),Copy the code
FittedBox
Resize and position the child widgets to their own size.
FittedBox(
fit: BoxFit.contain,
child: const FlutterLogo(),
)),
Copy the code
A layout widget with multiple child elements
Row
List the child widgets horizontally. To make child items expand to fill available horizontal space, wrap child items in Expanded widgets
body:Row(
children: <Widget>[
Expanded(child: Text('Deliver features faster',textAlign: TextAlign.center,)),
Expanded(child: Text('Craft beautiful UIs', textAlign: TextAlign.center)),
Expanded(child: FittedBox(
fit: BoxFit.contain,
child: const FlutterLogo(),
)),
],
)
Copy the code
Column
Row the list of child widgets vertically. To expand the child items to fill the available vertical space, wrap the child items in Expanded widgets.
Column(
children: <Widget>[
Text('Deliver features faster'),
Text('Craft beautiful UIs'),
Expanded(
child: FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: const FlutterLogo(),
),
),
],
)
Copy the code
Stack
You can allow the child widgets to be simply stacked on top of each other. This is useful if you want to overlap multiple child widgets in a simple way, for example, with some text and images, covered with gradients and buttons attached to the bottom.
Stack(
children: <Widget>[
Container(
width: 100,
height: 100,
color: Colors.red,
),
Container(
width: 90,
height: 90,
color: Colors.green,
),
Container(
width: 80,
height: 80,
color: Colors.blue,
),
],
)
Copy the code
IndexedStack
Displays a Stack of individual children from a list of child widgets, displaying the children with the given index. The stack is always as big as the biggest child. If value is null, nothing is displayed. Docs. Flutter. IO/flutter/wid…
Flow
A fluid layout algorithm widget docs. The flutter. IO/flutter/wid…
Table
Table layout algorithm for use its widgets widget docs. The flutter. IO/flutter/wid…
ListView
Scrollable list control. The ListView is the most commonly used scroll widget that displays its children one by one in the scrolling direction. On the vertical axis, the children are asked to populate the ListView.
Listview. builder(padding: EdgeInsets. All (8.0), itemExtent: 20.0, itemBuilder: listView. builder(padding: EdgeInsets. (BuildContext context, int index) { return Text('entry $index'); },)Copy the code
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class SecondPage extends StatefulWidget { String title; String url; SecondPage(this.title, this.url); // final snackBar = new SnackBar(content: new Text(title)); @override State<StatefulWidget> createState() { // TODO: implement createState return SecondPageState(); } } class SecondPageState extends State<SecondPage> { int a = 0; @override void initState() { super.initState(); setState(() { a++; Print (' state change '); }); } @override Widget build(BuildContext context) { return new Scaffold( appBar: AppBar( title: Text( '$a', style: TextStyle(color: Colors.white), ), iconTheme: IconThemeData(color: Colors.white), ), body: Listview. builder(itemExtent: 20.0, PADDING: EdgeInsets. All (8.0), itemCount: data.length, itemBuilder: (BuildContext context, int index) => new EntryItem(data[index]), // itemBuilder: (BuildContext context, int index) { // return Text('entry $index'); / /})); } } class Entry { final String title; final List<Entry> children; Entry(this.title, [this.children = const <Entry>[]]); } final List<Entry> data = <Entry>[new Entry('Section A0', [new Entry('Item A0.1'), New Entry('Item A0.2'), New Entry('Item A0.3'),]), New Entry('Section A1'), New Entry('Section A2'),], new Entry('Chapter B', <Entry>[ new Entry('Section B0'), new Entry('Section B1'), ]), new Entry('Chapter C', <Entry>[New Entry('Section C0'), New Entry('Section C1'), New Entry('Section C2', <Entry>[New Entry('Item C2.0'), New Entry (' Item C2.1 '), a new Entry (' Item C2.2 '), a new Entry (' Item C2.3 '),),),]; class EntryItem extends StatelessWidget { const EntryItem(this.entry); final Entry entry; Widget _buildTiles(Entry root) { if (root.children.isEmpty) return new ListTile( title: new Text(root.title), ); return new ExpansionTile( key: new PageStorageKey<Entry>(root), title: new Text(root.title), children: root.children.map(_buildTiles).toList(), ); } @override Widget build(BuildContext context) { // TODO: implement build return _buildTiles(entry); }}Copy the code