[Flutter Widget] layout

Posted flutter开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Flutter Widget] layout相关的知识,希望对你有一定的参考价值。

在上篇文章中我们主要介绍了Row和Column的用法,借助于这两个Widget我们可以很方便的完成我们想要的界面效果,按照惯例我们还是先来看下上节留下的问题。

根据前面学过的内容完成如下布局效果:

其实实现起来很简单,竖直方向是 Column里面children是多个Row对象,每个Row中分别对应Icon和Text,只不过Text需要使用Expanded包裹起来。

还是直接看代码吧:

import 'package:flutter/material.dart';

void main() {
 runApp(new MaterialApp(
   home: new MyApp(),
 
));
}

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new Scaffold(
     appBar: new AppBar(
       title: new Text("layout"),
     
),
     
body: new Column(
       children: <Widget>[
         new Container(
           padding: const EdgeInsets.all(10.0),
           
decoration: new BoxDecoration(
             border: new Border(
                 bottom: new BorderSide(
               color: Colors.grey,
             
)),
           
),
           
child: new Row(children: <Widget>[
             new Icon(
               Icons.chat,
               
color: Colors.lightBlueAccent,
             
),
             
new Expanded(
               child: new Text(
                 "消息记录",
                 
textAlign: TextAlign.right,
               
),
             
)
           ]),
         
),
         
new Container(
           padding: const EdgeInsets.all(10.0),
           
decoration: new BoxDecoration(
             border: new Border(
                 bottom: new BorderSide(
               color: Colors.grey,
             
)),
           
),
           
child: new Row(children: <Widget>[
             new Icon(
               Icons.stars,
               
color: Colors.lightBlueAccent,
             
),
             
new Expanded(
               child: new Text(
                 "我的收藏",
                 
textAlign: TextAlign.right,
               
),
             
)
           ]),
         
),
         
new Container(
           padding: const EdgeInsets.all(10.0),
           
decoration: new BoxDecoration(
             border: new Border(
                 bottom: new BorderSide(
               color: Colors.grey,
             
)),
           
),
           
child: new Row(children: <Widget>[
             new Icon(
               Icons.lock,
               
color: Colors.lightBlueAccent,
             
),
             
new Expanded(
               child: new Text(
                 "我的账户",
                 
textAlign: TextAlign.right,
               
),
             
)
           ]),
         
),
         
new Container(
           padding: const EdgeInsets.all(10.0),
           
decoration: new BoxDecoration(
             border: new Border(
                 bottom: new BorderSide(
               color: Colors.grey,
             
)),
           
),
           
child: new Row(children: <Widget>[
             new Icon(
               Icons.send,
               
color: Colors.lightBlueAccent,
             
),
             
new Expanded(
               child: new Text(
                 "意见反馈",
                 
textAlign: TextAlign.right,
               
),
             
)
           ]),
         
),
         
new Container(
           padding: const EdgeInsets.all(10.0),
           
decoration: new BoxDecoration(
             border: new Border(
                 bottom: new BorderSide(
               color: Colors.grey,
             
)),
           
),
           
child: new Row(children: <Widget>[
             new Icon(
               Icons.settings,
               
color: Colors.lightBlueAccent,
             
),
             
new Expanded(
               child: new Text(
                 "系统设置",
                 
textAlign: TextAlign.right,
               
),
             
)
           ]),
         
),
       
],
     
),
   
);
 
}
}

没错,根据上述代码我们确实可以实现上述图片的效果,但是我真的看不下去,因为实在太冗余了,相同的代码写了5遍,因为每一行的显示风格是一致的,只有图标和文字内容不同,这样一来我们就可以把这两个东西的组合给抽离出来组合成我们自定义的Widget

class MyListItem extends StatelessWidget {
 IconData myIcon;
 
String title;

 
MyListItem(this.myIcon, this.title);

 
@override
 
Widget build(BuildContext context) {
   // TODO: implement build
   
return new Container(
     padding: const EdgeInsets.all(10.0),
     
decoration: new BoxDecoration(
       border: new Border(bottom: new BorderSide(color: Colors.grey,)),
     
),
     
child: new Row(children: <Widget>[
       new Icon(
         myIcon,
         
color: Colors.lightBlueAccent,
       
),
       
new Expanded(
         child: new Text(
           title,
           
textAlign: TextAlign.right,
         
),
       
)
     ]),
   
);
 
}
}

可以看到,我们把每一行分装成一个MyListItem Widget,继承于StatelessWidget,构造方法传入一个IconData和一个String对象。

调用处代码:

import 'package:flutter/material.dart';

void main() {
 runApp(new MaterialApp(
   home: new MyApp(),
 
));
}

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new Scaffold(
     appBar: new AppBar(
       title: new Text("layout"),
     
),
     
body: new Column(
       children: <Widget>[
         new MyListItem(Icons.chat, "消息记录"),
         
new MyListItem(Icons.stars, "我的收藏"),
         
new MyListItem(Icons.lock, "我的账户"),
         
new MyListItem(Icons.send, "意见反馈"),
         
new MyListItem(Icons.settings, "系统设置"),
       
],
     
),
   
);
 
}
}

这样一来,我们每增加一行只需要在增加一个MyListItem对象即可。

好了,说完了Row和Column的用法,今天我们来快速的看下Table、Stack和IndexedStack,没错他们也都是Layout。

Table


在上一次的文章中我们介绍了类似表格布局的组件,那么今天我们就来正式介绍下Flutter中的表格布局Table

Table的构造方法如下:

Table({
Key key,
this.children: const <TableRow>[],
this.columnWidths,//列宽
this.defaultColumnWidth: const FlexColumnWidth(1.0),
this.textDirection,//文字方向
this.border,//边框
this.defaultVerticalAlignment: TableCellVerticalAlignment.top,//对齐方式
this.textBaseline//基线
})

可以看到和Row、Column一样同样需要传入一个children对象,只不过Table传入的children要求是多个TableRow对象而不是Widget对象。

好吧,还是再来看下TableRow这个东东

TableRow({ this.key, this.decoration, this.children })

好吧,真的很简单,只有两个参数,一个装饰器,一个children(Wdiget)

好吧,还是看下如何使用吧。

import 'package:flutter/material.dart';

void main() {
 runApp(new MaterialApp(
   home: new MyApp(),
 
));
}

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new Scaffold(
     appBar: new AppBar(
       title: new Text("Stack"),
     
),
     
body: new Table(
       children: <TableRow>[
         new TableRow(children: <Widget>[
           new Text(
             "姓名",
             
textAlign: TextAlign.center,
           
),
           
new Text("职位", textAlign: TextAlign.center)
         ]),
         
new TableRow(children: <Widget>[
           new Text("flyou", textAlign: TextAlign.center),
           
new Text("终端开发工程师", textAlign: TextAlign.center)
         ]),
         
new TableRow(children: <Widget>[
           new Text("张三", textAlign: TextAlign.center),
           
new Text("Java开发工程师", textAlign: TextAlign.center)
         ]),
         
new TableRow(children: <Widget>[
           new Text("李四", textAlign: TextAlign.center),
           
new Text("大数据开发工程师", textAlign: TextAlign.center)
         ]),
         
new TableRow(children: <Widget>[
           new Text("王五", textAlign: TextAlign.center),
           
new Text("Python数据工程师", textAlign: TextAlign.center)
         ])
       ],
     
),
   
);
 
}
}

[Flutter Widget] layout(2)

可以看到,上面的数据就按照行和列显示了,接下来我们使用border属性给表格加上分割线。

border: new TableBorder.all(color: Colors.grey),

[Flutter Widget] layout(2)

当然,大家可以根据自己的需要选择一行有几列,或者自定义表格的border。接下来我们来看看Stack和IndexedStack

Stack


按照翻译来讲的话是栈布局的意思,其实也很贴切,最先放入的必然在最下面显示。

构造方法:

Stack({
Key key,
this.alignment: AlignmentDirectional.topStart,//对齐方式
this.textDirection,
this.fit: StackFit.loose,//是否按照父类宽高处理自己大小
this.overflow: Overflow.clip,//溢出处理方式
List<Widget> children: const <Widget>[],
})

还是看下如何使用吧:

import 'package:flutter/material.dart';

void main() {
 runApp(new MaterialApp(
   home: new MyApp(),
 
));
}

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new Scaffold(
     appBar: new AppBar(
       title: new Text("Stack"),
     
),
     
body: new Stack(

       children: <Widget>[
         new Icon(
           Icons.check_circle,
           
size: 100.0,
           
color: Colors.yellow,
         
),
         
new Icon(Icons.check_circle,   color: Colors.lightGreen,)

       ],
       
alignment: Alignment.bottomRight,
     
),
   
);
 
}
}

看下上面的代码,我们在Stack的children中放入了两个icons一个大小为100的黄色对号,一个是为默认大小的绿色对号,绿色的下图标小时在又下角。

[Flutter Widget] layout(2)

也就是说,栈布局,默认后面放入的Widget会覆盖在前面放入的Widget上面显示。当然这个跟android上面的帧布局是比较相似,在布局中还是有很多实用场景的。

接下来我们来看下Stack的兄弟IndexedStack

IndexedStack


在上面我们看了下Stack,基本上知道了Stack的用法,其实IndexedStack的用法和Stack一样,只不过IndexedStack只显示指定位置的Widget,其他的位置的Widget不会显示。

new IndexedStack(
index: 1,
children: <Widget>[
new Icon(
Icons.check_circle,
size: 100.0,
color: Colors.green,
),
new Icon(
Icons.error_outline,
size: 100.0,
color: Colors.red,
)
],
alignment: Alignment.bottomRight,
)

从上面代码可以看出来,我们定义了两个Icon,第一个是一个绿色的对号,第二个是一个红色的感叹号,仅仅比上面的Stack多了一个index为1(默认为0)参数,运行代码

如index填为0或者不填,则会显示第一个Widget中的内容

其实这个IndexedStack还是很有用的,比如说你的应用现实的额多个状态(加载中、加载完成、网络错误)可以使用这个组件来很好的完成控制。

小结


通过自定义组件优化布局代码

Stack、和IndexedStack都是栈布局
IndexedStack指定显示指定位置的一个Widget

试一试


我能告诉你今天没有这个环节吗,哈


当然,有什么问题也欢迎大家在后台留言,我会在看到的第一时间回复大家的



以上是关于[Flutter Widget] layout的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Transform使用介绍

flutter 系列之:flutter 中常用的 GridView layout 详解

Flutter原理—布局绘制

Flutter原理—布局绘制

Flutter原理—布局绘制

Flutter 加载中视图失败视图空视图封装