flutter文件是由 widget 渲染而成的,而 widget 存在 widget 树的概念,这表示一个布局的渲染可以以树的形式表示出来。
MaterialApp
假设我们现在有一段widget的代码,我们希望把它呈现在app的界面上,一般来说我会选择 MaterialApp,这里面有数个符合 Material Design 原则的 widgets。既然提到了就浅浅讲解下几个比较常用的参数,再多的其实我也不会了。
参数 | 值 | 备注 |
---|---|---|
home | widget | 主页。一般来说会放一个 Scaffold() 包住的代码。 |
theme | ThemeData | 主题。一般就 ThemeData.dark() 和 ThemeData.light(),可以改 primaryColor 修改light 主题时蓝色主色调 |
title | String | 应用程序的标题 |
routes | Map<String,WidgetBuilder> | 路由。应用的顶级导航表格,这个是多页面应用用来控制页面跳转的,类似于网页的网址 |
initialRoute | String | 第一个显示的路由名字 |
debugShowMaterialGrid | bool | 显示网格,debug的时候看的 |
showPerformanceOverlay | bool | 显示性能标签 |
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Love Story',
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.yellowAccent,
),
debugShowMaterialGrid: true,
showPerformanceOverlay: true,
);
}
}
主题颜色变到这里去了,有点小奇怪
横纵向布局(嵌套)
Row, Column
一般来说就是指横向和纵向 Row, Column,比如说这段代码。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Love Story',
theme: ThemeData(
brightness: Brightness.light,
// primaryColor: Colors.yellowAccent,
),
// debugShowMaterialGrid: true,
// showPerformanceOverlay: true,
home: RowColumn(),
);
}
}
class RowColumn extends StatelessWidget {
const RowColumn({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Image.asset("assets/images/1.jpg"),
flex: 40,
),
const Spacer(
flex: 3,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("11111", style: TextStyle(fontSize: 30)),
const Padding(padding: EdgeInsets.only(bottom: 20.0)),
Text("222222", style: TextStyle(fontSize: 20)),
const Padding(padding: EdgeInsets.only(bottom: 10.0)),
Text("33333", style: TextStyle(fontSize: 16)),
const Padding(padding: EdgeInsets.only(bottom: 1.0)),
Text("33333", style: TextStyle(fontSize: 16)),
const Padding(padding: EdgeInsets.only(bottom: 1.0)),
Text("33333", style: TextStyle(fontSize: 16)),
],
),
],
),
);
}
}
尽管效果看上去十分阴间,但是可以分辨出图片和文字组的关系是 row,文字和文字之间的关系是column。
ListTile
ListTile 是一个易于使用的 widget,有属性可以设置头尾图标,最多可以显示 3 行文本。ListTile 可以一定程度上代替 Row,我们在下面演示一下:
代码:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Love Story',
theme: ThemeData(
brightness: Brightness.light,
// primaryColor: Colors.yellowAccent,
),
home: RowListTile(),
);
}
}
class RowListTile extends StatelessWidget {
const RowListTile({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const Text("\n\nRow\n\n\n"),
Card(
child: Row(
children: [
FlutterLogo(size: 72.0),
Text('Three-line ListTile'),
Text(
'This is a subtitle'
),
Icon(Icons.more_vert),
],
),
),
const Text("ListTile\n\n\n"),
const Card(
child: ListTile(
// 头图标
leading: FlutterLogo(size: 72.0),
// 第一行
title: Text('Three-line ListTile'),
// 第二行
subtitle: Text(
'This is a subtitle'
),
// 尾图标
trailing: Icon(Icons.more_vert),
isThreeLine: true,
),
),
]
),
);
}
}
ListView
ListView 是一种类似于列的布局,官网说如果 ListView 内容太长导致可用空间不够容纳时会自动滚动,我试了半天没试出来。效果只能是这样了。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Love Story',
theme: ThemeData(
brightness: Brightness.light,
// primaryColor: Colors.yellowAccent,
),
home: ColumnListView(),
);
}
}
class ColumnListView extends StatelessWidget {
const ColumnListView({Key? key}) : super(key: key);
Widget build(BuildContext context) {
final List<String> entries = <String>['A', 'B', 'C', 'D', 'E', 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'];
final List<int> colorCodes = <int>[600, 500, 400, 300, 200, 100];
return Scaffold(
body: Column(
children: [
Column(
children: [
Text("1111111111111111111111111111111111111111111111111111111111111111"),
Text("222222"),
],
),
ListView.separated(
// 这个参数绝对不能省略
shrinkWrap: true,
padding: const EdgeInsets.all(8),
// 自带的迭代器,可以实现循环类似的功能
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
);
},
// 分割符号
separatorBuilder: (BuildContext context, int index) => const Divider(),
// 提前告诉ListView下有几个items
itemCount: entries.length
),
]
),
);
}
}
微调
这部分我在 widget 那篇博客中详细介绍尝试过,这里针对几个小效果和提一下几种用法。
- 水平分布与垂直分布布局平分空白部分
- 元素大小自动调整
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Love Story',
theme: ThemeData(
brightness: Brightness.light,
// primaryColor: Colors.yellowAccent,
),
home: VerticalHorizontal(),
);
}
}
class VerticalHorizontal extends StatelessWidget {
// const VerticalHorizontal({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Column(
children:[
Row(
// 平分空位,因为白比蓝宽,所以看起来居中点
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
children:[
Icon(Icons.widgets,size: 50, color: Colors.white,),
Icon(Icons.widgets,size: 50, color: Colors.white,),
Icon(Icons.widgets,size: 50, color: Colors.white,),
]
),
Column(
children:[
Icon(Icons.widgets,size: 50, color: Colors.blue,),
Icon(Icons.widgets,size: 50, color: Colors.blue,),
Icon(Icons.widgets,size: 50, color: Colors.blue,),
]
)
]
),
Row(
children: [
// 正常情况下这三张图片过大,放不下,都套一个Expanded让他们正常
Expanded(child: Image.asset("assets/images/1.jpg"),),
// 2倍权重,大小是别人的两倍
Expanded(child: Image.asset("assets/images/2.jpg"),flex: 2,),
Expanded(child: Image.asset("assets/images/3.jpg"),),
],
)
]
);
}
}