在讲布局之前先说说获取屏幕宽高的方法:
final size =MediaQuery.of(context).size;
final width =size.width;
final height =size.height;
布局
1. 水平布局
/**
*
* 自定义组件的水平布局-- Row
*
*/
class MyLayout01 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
color: Color.fromRGBO(233, 233, 233, 1.0),
height: 600,
width: 400,
child: Row(
// 子控件所在父控件的布局方式
crossAxisAlignment: CrossAxisAlignment.start,
// 子控件的布局方式,start: 靠左,end:靠右,spaceEvenly: 均匀分布
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MyIconContainer01(Icons.home,color: Colors.blue,),
MyIconContainer01(Icons.search,color: Colors.pink,),
MyIconContainer01(Icons.send,color:Colors.yellow)
],
),
);
}
}
2. 水平布局和垂直( Column )布局的
/**
*
* Layout布局的demo
*/
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Container(
height: 180,
color: Colors.black,
child: Text('你好flutter'),
),
)
],
),
SizedBox(height: 10,),
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
height: 180,
child: Image.network("https://www.itying.com/images/flutter/2.png",fit: BoxFit.cover,),
),
),
SizedBox(width: 10,),
Expanded(
flex: 1,
child: Container(
height: 180,
child: ListView(
children: <Widget>[
Container(
height: 90,
child: Image.network("https://www.itying.com/images/flutter/3.png",fit: BoxFit.cover,),
),
SizedBox(height: 10,),
Container(
height: 90,
child:Image.network("https://www.itying.com/images/flutter/1.png",fit: BoxFit.cover,),
),
],
)
),
)
],
)
],
);
}
}
3. Stack层叠组件布局
/**
*
* Stack组件, 自由定位子控件,相当于前端的悬浮
*
*/
class MyStackLayout01 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Stack(
// alignment: Alignment.center,
// Alignment这里面的参数,x,y是-1到1之间变化,就可以达到定位的效果
alignment: Alignment(-1,1),
children: <Widget>[
Container(
height: 400,
width: 300,
color: Colors.red,
),
Text("我是一个文本"),
Text("我是一个文本22"),
Text("我是一个文本454"),
Text("我是一个文本54题4"),
],
),
);
}
}
4. Stack层叠组件 结合Align 给多个子组件布局
/**
*
* Stack组件--结合Align给多个子控件布局
*
*/
class MyStackLayout02 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.yellow,
child: Stack(
// alignment: Alignment.center,
// Alignment这里面的参数,x,y是-1到1之间变化,就可以达到定位的效果
alignment: Alignment(-1,1),
children: <Widget>[
Align(
alignment: Alignment(0, 0),
child: Icon(Icons.home,size: 40,color: Colors.blue,),
),
Align(
alignment: Alignment(0, 1),
child: Icon(Icons.select_all,size: 40,color: Colors.green,),
),
Align(
alignment: Alignment(1, 0),
child: Icon(Icons.satellite,size: 40,color: Colors.red,),
),
Align(
alignment: Alignment(1, 1),
child: Icon(Icons.save,size: 40,color: Colors.pink,),
),
],
),
),
);
}
}
5. Stack层叠组件 结合Positioned给多个子控件布局
/**
*
* Stack组件--结合Positioned给多个子控件布局
*
*/
class MyStackLayout03 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.yellow,
child: Stack(
// alignment: Alignment.center,
// Alignment这里面的参数,x,y是-1到1之间变化,就可以达到定位的效果
alignment: Alignment(-1,1),
children: <Widget>[
Positioned(
left: 0,
top: 0,
child: Icon(Icons.home,size: 40,color: Colors.blue,),
),
Positioned(
right: 0,
top: 0,
child: Icon(Icons.select_all,size: 40,color: Colors.green,),
),
Positioned(
bottom: 0,
child: Icon(Icons.satellite,size: 40,color: Colors.red,),
),
Positioned(
bottom: 0,
right: 0,
child: Icon(Icons.save,size: 40,color: Colors.pink,),
),
],
),
),
);
}
}
6. AspectRatio组件
/**
*
* AspectRatio组件
*/
class MyAspectRatio extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return AspectRatio(
// aspectRatio 表示宽高比, 这里宽是占满整屏幕的
aspectRatio: 3.0/1.0,
child: Container(
color: Colors.red,
),
);
}
}
7. 卡片组件
/**
* 卡片布局 -- Card
*/
class MyCard01 extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: <Widget>[
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"张三",
style: TextStyle(fontSize: 28),
),
subtitle: Text("高级工程师傅"),
),
ListTile(
title: Text("电话:XXXXXX"),
),
ListTile(
title: Text("地址:XXXXXX"),
),
],
),
),
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"张三",
style: TextStyle(fontSize: 28),
),
subtitle: Text("高级工程师傅"),
),
ListTile(
title: Text("电话:XXXXXX"),
),
ListTile(
title: Text("地址:XXXXXX"),
),
],
),
)
],
);
}
}
8. Card-- 商品的图文布局
/**
* 卡片布局 -- Card -- 具有图文的卡片
*/
class MyCard02 extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: <Widget>[
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
// 纵横比例
aspectRatio: 20/9,
child: Image.network("https://www.itying.com/images/flutter/2.png",fit: BoxFit.cover,),
),
ListTile(
// CircleAvatar这个控件专门设置头像的
leading: CircleAvatar(
backgroundImage: NetworkImage("https://www.itying.com/images/flutter/1.png"),
),
title: Text("姓名:xxxxxxxx"),
subtitle: Text("电话:xxxxxx"),
)
],
),
),
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 20/9,
child: Image.network("https://www.itying.com/images/flutter/2.png",fit: BoxFit.cover,),
),
ListTile(
// ClipOval实现圆图片
leading: ClipOval(
child: Image.network("https://www.itying.com/images/flutter/3.png",height: 40,width: 40,fit: BoxFit.cover,),
),
title: Text("姓名:xxxxx"),
subtitle: Text("电话:xxxxx"),
)
],
),
)
],
);
}
}
9. 卡片布局 -- Card -- 用本地数据模拟网络数据,加载有图文的卡片
/**
* 卡片布局 -- Card -- 用本地数据模拟网络数据,加载有图文的卡片
*/
class MyCard03 extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: listData.map((value){
return Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 20/9,
child: Image.network(value["imageUrl"],fit: BoxFit.cover,),
),
ListTile(
title: Text(value["title"]),
subtitle: Text(value["author"]),
)
],
),
);
}).toList()
);
}
}
10. wrap组件布局方式
wrap组件相当于就是一个流式布局,比如很多按钮,按照x轴去排列,如果排列不下,就换一行继续排列,与Row布局 和Column布局方式是一起的
在讲wrap组件之间,先讲讲按钮组件
class MyWrapLayout01 extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
height: 600,
width: double.infinity, // 这个写法就是表示占满整个屏幕
child: Wrap(
spacing: 10,// 间距
// runSpacing: 10, // 垂直方向间距
alignment: WrapAlignment.start, // 左对齐方式
// direction: Axis.vertical, // 垂直方向排列
children: <Widget>[
MyRaisedButton("第1集"),
MyRaisedButton("第10集"),
MyRaisedButton("第110集"),
MyRaisedButton("第1101集"),
MyRaisedButton("第1123集"),
MyRaisedButton("第1543集"),
MyRaisedButton("第1435集"),
MyRaisedButton("第154325集"),
MyRaisedButton("第15435集"),
MyRaisedButton("第153245集"),
MyRaisedButton("第431集"),
],
)
);
// TODO: implement build
}
}
/**
* 按钮组件RaisedButton
*/
class MyRaisedButton extends StatelessWidget{
final String text;
const MyRaisedButton(this.text,{Key key});
// const MyRaisedButton(this.text,{Key key});
@override
Widget build(BuildContext context) {
// TODO: implement build
return RaisedButton(
child: Text(this.text),
onPressed: () {
print(this.text);
},
textColor: Theme.of(context).accentColor
);
}
}
二, Tabbar
1. Flutter中自定义有状态组件 StatefullWidget
在flutter中自定义组件其实就是一个类,这个类需要继承StatelessWidget或者Statefullwidget
- StatelessWidget是无状态组件,状态不可变的widget
- Statefullwidget是有状态组件,持有状态可能在widget生命周期改变,如果想要改变页面中的数据的话,这个时候就需要用到StatefulWidget
下面代码实现,点击按钮,可以改变上面的数据
/**
* 有状态组件
*/
class MyStateFul01 extends StatefulWidget {
MyStateFul01({Key key}) : super(key: key);
_MyStateFul01State createState() => _MyStateFul01State();
}
class _MyStateFul01State extends State<MyStateFul01> {
int countNum = 0;
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
SizedBox(height: 100,),
Chip(
label: Text("${this.countNum}"),
),
RaisedButton(
onPressed: () {
setState(() {
this.countNum++;
});
},
child: Text("这是一个按钮"),
)
],
),
);
}
}
第二份代码,实现点击按钮,给list添加数据,把数据展示在listView上
/**
* 有状态组件 点击按钮实现改变数据01
*/
class MyStateFul02 extends StatefulWidget {
MyStateFul02({Key key}) : super(key: key);
_MyStateFul02State createState() => _MyStateFul02State();
}
class _MyStateFul02State extends State<MyStateFul02> {
List list = new List();
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Column(
children: this.list.map((value){
return ListTile(
title: Text(value),
);
}).toList(),
),
RaisedButton(
onPressed: () {
setState(() {
this.list.add("添加一条数据01");
});
},
child: Text("按钮"),
)
],
);
}
}
2. 通过有状态组件封装tabbar
以下代码可以实现点击tabbar的效果
/**
* 抽离tabbar组件 -- 有状态
*/
class Tabbar extends StatefulWidget {
Tabbar({Key key}) : super(key: key);
_TabbarState createState() => _TabbarState();
}
class _TabbarState extends State<Tabbar> {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("首页"),
),
// body: MyIconContainer01(Icons.search,color: Colors.black),
body: MyStateFul02(),
// 实现底部tabbar
bottomNavigationBar: BottomNavigationBar(
currentIndex: this._currentIndex, // 初始化在哪个bar
onTap: (int index){
setState(() {
this._currentIndex = index;
});
},
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("首页")
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
title: Text("附近")
),
BottomNavigationBarItem(
icon: Icon(Icons.my_location),
title: Text("我的")
),
],
)
);
}
}
// 在MyApp中
home: Tabbar(),即可