本文章分别介绍Container,Stack,Positioned三个组件各自用途,然后组合在一个框架中实现一个简单案例。
image.png
首先创建Flutter应用
flutter create my_widget
打开文件lib/main.dart
并将其修改为
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("组件"),
),
body: Container(
margin: EdgeInsets.all(10),
color: Colors.pinkAccent,
)
),
);
}
}
上述代码中,我们通过调整颜色并提供margin来使用Container创建对象。EdgeInsets.all()
这意味着要在(左,上、右、下)留出空间。
进一步修改main.dart文件
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("组件"),
),
body: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(15),
color: Colors.pinkAccent,
child: Container(
decoration: BoxDecoration(
color: Colors.lightGreen,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.lightGreen, Colors.limeAccent],
),
borderRadius: BorderRadius.circular(30),
boxShadow: <BoxShadow>[
BoxShadow(blurRadius: 10),
],
),
),
)
),
);
}
}
容器中放置容器,上面代码制作了一个大的粉红色盒子,盒子里放置一个源变色的盒子。通过BoxDecoration
的borderRadius
制作盒子的圆角。注:decoration
还有很多属性进行自定义的容器样式设置。
Stack & Positioned
Stack的children下可放置多个组件,Positioned
可以指定组件放置位置。
修改lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("组件"),
),
body: Stack(
children: <Widget>[
Container(
color: Colors.orangeAccent,
height: 250,
),
Positioned(
top: 195,
left: 155,
child: Container(
height: 50,
width: 250,
color: Colors.black38,
child: Center(
child: Text(
"Stack & Positioned",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
)
],
),
),
);
}
}
创建用户界面
首先通过borderRadius
对粉红色的容器做底部弯曲。第二是一个白色背景的容器通过positioned
定位在上面。最后通过Card
实现收支历史记录(今后会使用ListView替代)。
打开lib/main.dart
并将其修改为
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage()
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final double screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text("AppBar"),
backgroundColor: Colors.transparent, //透明化
elevation: 0.0, //去除阴影效果
),
extendBodyBehindAppBar: true, //扩展body的高度到AppBar下面
body: Container(
//子组件里包含Stack标题和Card历史记录
child: Column(
children: <Widget>[
Stack(
overflow: Overflow.visible,
children: <Widget>[backgroundHeader(), summaryCash(screenWidth)],
),
SizedBox(height: 55),
//展示收支历史记录
cardDetail('午餐', '肯德基', '10.000', 'out'),
cardDetail('现金收入', '获取项目奖金', '500.000', 'in'),
cardDetail('买衣服', '办公T恤', '250.000', 'out'),
],
),
),
);
}
}
Widget backgroundHeader() {
//标题显示
}
Widget summaryCash(double screenWidth) {
//汇总数据显示
}
Widget cardDetail(title, description, price, type) {
//历史记录
}
上述代码把“标题”、“摘要”和“卡片”部分拆分,以使代码解耦
接下来首先处理标题,函数修改如下:
Widget backgroundHeader() {
//高300的容器,底部圆角
return Container(
height: 220,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.pinkAccent,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
),
//使用Padding填充页面
child: Padding(
//顶部显示信息
padding: const EdgeInsets.only(top: 80, left: 20),
//使用Column显示多个组件
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"刘裕",
style: TextStyle(
fontSize: 25, color: Colors.white, fontWeight: FontWeight.bold),
),
Text(
"1869999999",
style: TextStyle(
fontSize: 15,
color: Colors.white,
),
),
],
),
),
);
}
运行上述代码,则会显示一个粉红色背示的标题,其中包含2个文本。接下来是在标题上方放置一个摘要,修改函数summaryCash()
如下:
Widget summaryCash(double screenWidth) {
return Positioned(
top: 160,
left: 20,
child:Opacity(
opacity: 0.9,
child: Container(
width: screenWidth * 0.9,
height: 120,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 6.0,
),
],
),
//设置容器内部填充布局
child: Padding(
padding: const EdgeInsets.only(top: 30.0),
//使用Row()对两列数据进行放置
child: Row(
//通过行对列数据进行布局
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//在同一行内垂直排放两列数据
Column(
children: <Widget>[
Text("收入"),
Divider(),
Text(
"RMB 500.00",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
Column(
children: <Widget>[
Text("支出"),
Divider(),
Text(
"RMB 260.00",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
],
),
),
),
),
);
}
最后一部分是制做card历史记录,修改函数cardDetail()
如下:
//封装可重用的Card,需提供title, description, price, type
Widget cardDetail(title, description, price, type) {
return Card(
//定制Card边距
margin: EdgeInsets.only(top: 15, left: 15, right: 15),
//阴影度为8
elevation: 8,
child: ListTile(
leading: Icon(
type == 'out'
? Icons.subdirectory_arrow_left
: Icons.subdirectory_arrow_right,
color: type == 'out' ? Colors.redAccent : Colors.lightGreen,
),
title: Text(
title,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(description),
trailing: Text(
"RMB " + price,
style: TextStyle(
color: type == 'out' ? Colors.redAccent : Colors.lightGreen),
),
),
);
}
保存并运行程序,结果如最初附图一致,此例中仅使用了Container,Stack和Positioned制作一个简单的UI。
网友评论