MaterialApp
对于
MaterialApp
,组件提供了一些默认的属性,如AppBar
、标题
、背景颜色
等,你可以默认使用它们
import 'package:flutter/material.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
/**
* MaterialApp
*/
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: const Text('标题'),
),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}
非 MaterialApp
默认情况下,
非 MaterialApp
不包含AppBar
、标题
和背景颜色
,如希望实现这些功能,则必须手动构建它们
import 'package:flutter/material.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
/**
* 非MaterialApp
*/
return Container(
decoration: const BoxDecoration(color: Colors.grey),
child: const Center(
child: Text(
'Hello Lee!',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
));
}
}
Row、Column 布局
实现 Select
组件
Select组件
(lib/components/select_widget.dart
)
import 'package:flutter/material.dart';
// 定义Option
class SelectOption {
String label;
Object value;
SelectOption({required this.label, required this.value});
}
// Select组件
class SelectWidget extends StatefulWidget {
final String title;
late final List<SelectOption> options;
final ValueChanged<SelectOption> onChange; // 监听选择
SelectWidget({super.key, required this.title, required List<SelectOption> options, required this.onChange}) {
this.options = options.isNotEmpty ? options : [SelectOption(label: '', value: '')];
}
State<SelectWidget> createState() => _SelectWidgetState();
}
class _SelectWidgetState extends State<SelectWidget> {
int current = 0;
Widget build(BuildContext context) {
return Container(
height: 50,
padding: const EdgeInsets.only(top: 5, bottom: 5),
decoration: BoxDecoration(color: Colors.cyan, border: Border.all(width: double.minPositive, color: Colors.black)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.title, style: const TextStyle(color: Colors.white, fontSize: 12)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 24,
height: 24,
child: IconButton(
padding: const EdgeInsets.all(0),
color: Colors.white,
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: const Icon(Icons.arrow_left),
onPressed: _prev,
),
),
Center(
child: Text(
widget.options[current].label,
style: const TextStyle(color: Colors.yellow, fontSize: 12),
),
),
SizedBox(
width: 24,
height: 24,
child: IconButton(
padding: const EdgeInsets.all(0),
color: Colors.white,
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: const Icon(Icons.arrow_right),
onPressed: _next,
),
),
],
),
],
),
);
}
// 上一个option
_prev() {
setState(() {
if (current > 0) {
current--;
} else {
current = widget.options.length - 1;
}
widget.onChange(widget.options[current]);
});
}
// 下一个option
_next() {
setState(() {
if (current < widget.options.length - 1) {
current++;
} else {
current = 0;
}
widget.onChange(widget.options[current]);
});
}
}
引用页面
(lib/views/SelectPage.dart
)
import 'package:flutter/material.dart';
import 'package:flutter_app/components/select_widget.dart';
class SelectPage extends StatefulWidget {
const SelectPage({super.key});
State<SelectPage> createState() => _SelectPage();
}
class _SelectPage extends State<SelectPage> {
String text = '天津 - TianJin';
List<SelectOption> addressList = [
SelectOption(label: '天津', value: 'TianJin'),
SelectOption(label: '北京', value: 'BeiJing'),
];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Select')),
body: Column(
children: [
Container(
margin: const EdgeInsets.all(10),
height: 51,
child: SelectWidget(
title: '区域',
options: addressList,
onChange: (SelectOption option) {
setState(() {
text = "${option.label} - ${option.value}";
print(text);
});
},
),
),
Text(text)
],
),
);
}
}
使用Select
实现切换Row
、Column
属性
布局页面
(lib/views/layout.dart
)
import 'package:flutter/material.dart';
import '../components/select_widget.dart';
enum LayoutType { row, column }
enum ContentType { container, text }
class Layout extends StatefulWidget {
const Layout({super.key});
State<Layout> createState() => _Layout();
}
class _Layout extends State<Layout> {
ContentType contentValue = ContentType.container;
List<SelectOption> contentList = <SelectOption>[
SelectOption(label: 'Container', value: ContentType.container),
SelectOption(label: 'Text', value: ContentType.text),
];
LayoutType layoutValue = LayoutType.row;
List<SelectOption> layoutList = <SelectOption>[
SelectOption(label: 'Row', value: LayoutType.row),
SelectOption(label: 'Column', value: LayoutType.column),
];
MainAxisAlignment mainAxisAlignmentValue = MainAxisAlignment.start;
List<SelectOption> mainAxisAlignmentList = <SelectOption>[
SelectOption(label: 'start', value: MainAxisAlignment.start),
SelectOption(label: 'end', value: MainAxisAlignment.end),
SelectOption(label: 'center', value: MainAxisAlignment.center),
SelectOption(label: 'spaceBetween', value: MainAxisAlignment.spaceBetween),
SelectOption(label: 'spaceEvenly', value: MainAxisAlignment.spaceEvenly),
SelectOption(label: 'spaceAround', value: MainAxisAlignment.spaceAround),
];
MainAxisSize mainAxisSizeValue = MainAxisSize.min;
List<SelectOption> mainAxisSizeList = <SelectOption>[
SelectOption(label: 'min', value: MainAxisSize.min),
SelectOption(label: 'max', value: MainAxisSize.max),
];
CrossAxisAlignment crossAxisAlignmentValue = CrossAxisAlignment.start;
List<SelectOption> crossAxisAlignmentList = <SelectOption>[
SelectOption(label: 'start', value: CrossAxisAlignment.start),
SelectOption(label: 'end', value: CrossAxisAlignment.end),
SelectOption(label: 'center', value: CrossAxisAlignment.center),
SelectOption(label: 'stretch', value: CrossAxisAlignment.stretch),
SelectOption(label: 'baseline', value: CrossAxisAlignment.baseline),
];
TextDirection textDirectionValue = TextDirection.ltr;
List<SelectOption> textDirectionList = <SelectOption>[
SelectOption(label: 'ltr', value: TextDirection.ltr),
SelectOption(label: 'rtl', value: TextDirection.rtl),
];
VerticalDirection verticalDirectionValue = VerticalDirection.up;
List<SelectOption> verticalDirectionList = <SelectOption>[
SelectOption(label: 'up', value: VerticalDirection.up),
SelectOption(label: 'down', value: VerticalDirection.down),
];
TextBaseline textBaselineValue = TextBaseline.alphabetic;
List<SelectOption> textBaselineList = <SelectOption>[
SelectOption(label: 'alphabetic', value: TextBaseline.alphabetic),
SelectOption(label: 'ideographic', value: TextBaseline.ideographic),
];
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(150),
child: Column(
children: [
// 属性
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 1,
child: SelectWidget(
title: 'ContentType',
options: contentList,
onChange: (SelectOption selectOption) {
setState(() {
contentValue = selectOption.value as ContentType;
});
},
),
),
Expanded(
flex: 1,
child: SelectWidget(
title: 'Layout',
options: layoutList,
onChange: (SelectOption selectOption) {
setState(() {
layoutValue = selectOption.value as LayoutType;
});
},
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 1,
child: SelectWidget(
title: 'MainAxisAlignment',
options: mainAxisAlignmentList,
onChange: (SelectOption selectOption) {
setState(() {
mainAxisAlignmentValue = selectOption.value as MainAxisAlignment;
});
},
),
),
Expanded(
flex: 1,
child: SelectWidget(
title: 'MainAxisSize',
options: mainAxisSizeList,
onChange: (SelectOption selectOption) {
setState(() {
mainAxisSizeValue = selectOption.value as MainAxisSize;
});
},
),
),
Expanded(
flex: 1,
child: SelectWidget(
title: 'CrossAxisAlignment',
options: crossAxisAlignmentList,
onChange: (SelectOption selectOption) {
setState(() {
crossAxisAlignmentValue = selectOption.value as CrossAxisAlignment;
});
},
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 1,
child: SelectWidget(
title: 'TextDirection',
options: textDirectionList,
onChange: (SelectOption selectOption) {
setState(() {
textDirectionValue = selectOption.value as TextDirection;
});
},
),
),
Expanded(
flex: 1,
child: SelectWidget(
title: 'VerticalDirection',
options: verticalDirectionList,
onChange: (SelectOption selectOption) {
setState(() {
verticalDirectionValue = selectOption.value as VerticalDirection;
});
},
),
),
Expanded(
flex: 1,
child: SelectWidget(
title: 'TextBaseline',
options: textBaselineList,
onChange: (SelectOption selectOption) {
setState(() {
textBaselineValue = selectOption.value as TextBaseline;
});
},
),
),
],
),
],
),
),
body: Container(
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.black12, border: Border.all(width: 1, color: Colors.grey)),
child: layoutValue == LayoutType.row
? Row(
mainAxisAlignment: mainAxisAlignmentValue,
mainAxisSize: mainAxisSizeValue,
crossAxisAlignment: crossAxisAlignmentValue,
textDirection: textDirectionValue,
verticalDirection: verticalDirectionValue,
textBaseline: textBaselineValue,
children: contentValue == ContentType.container
? [
Container(color: Colors.red, width: 100, height: 70),
Container(color: Colors.green, width: 60, height: 90),
Container(color: Colors.blue, width: 80, height: 50),
]
: [
const Text('Red', style: TextStyle(fontSize: 20, backgroundColor: Colors.red)),
const Text('Green', style: TextStyle(fontSize: 50, backgroundColor: Colors.green)),
const Text('Blue', style: TextStyle(fontSize: 30, backgroundColor: Colors.blue)),
],
)
: Column(
mainAxisAlignment: mainAxisAlignmentValue,
mainAxisSize: mainAxisSizeValue,
crossAxisAlignment: crossAxisAlignmentValue,
textDirection: textDirectionValue,
verticalDirection: verticalDirectionValue,
textBaseline: textBaselineValue,
children: contentValue == ContentType.container
? [
Container(color: Colors.red, width: 100, height: 70),
Container(color: Colors.green, width: 60, height: 90),
Container(color: Colors.blue, width: 80, height: 50),
]
: [
const Text('Red', style: TextStyle(fontSize: 20, backgroundColor: Colors.red)),
const Text('Green', style: TextStyle(fontSize: 50, backgroundColor: Colors.green)),
const Text('Blue', style: TextStyle(fontSize: 30, backgroundColor: Colors.blue)),
],
),
),
);
}
}
页面入口
(lib/main.dart
)
import 'package:flutter/material.dart';
import 'package:flutter_app/views/layout.dart';
void main() {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Row、Column 布局')),
body: const Layout(),
),
);
}
}