Flutter基础填坑

      发布在:前端技术      评论:0 条评论

[TOC]

关于 Flutter 是什么就不再过多阐述了,网上已经有了很多相关文献
####安装(MacOS)
首先必须保证电脑有这些东西,没有请下载
- brew
- Xcode(AppStore 可下载)
- Android Studio

前往 flutter 官网下载 SDK
解压它 然后放到你常用的软件包位置
根据环境找到你的.zshrc或者.bashrc
加入

export PATH=$HOME/flutter/bin:$PATH

这里的路径指向你刚才放 flutter 的文件夹路径
然后试一下flutter -h能否出帮助 如果可以则 flutter 安装正常,接下来安装 flutter 依赖
首先控制台里输flutter doctor
OK,到这里你会发现有几个项目前面有感叹号,我们一个一个来解决
Flutter基础填坑
首先是这一项,前面假设你已经安装过 Android Studio 那么现在你只需要允许协议

flutter doctor --android-licenses

接下来 flutter 会问你几个问题 这里一路按 y 即可
然后是 IOS 开发这边,当出现

brew update
brew install --HEAD usbmuxd
brew link usbmuxd
brew install
brew install --HEAD libimobiledevice
brew install ideviceinstaller

先尝试着跟着敲一次,如果发现 brew install --HEAD usbmuxd的时候各种报pkg-config 的错,请不要犹豫 直接先把 brew 卸载

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)"

再次安装usbmuxd就可以了
最后剩下三条命令

brew install ios-deploy
brew install cocoapods
pod setup

依次敲即可 这里没有太大问题。
然后再次flutter doctor
Flutter基础填坑
这样就是正常了 如果你发现最后一项感叹号那只是因为你没有插手机或者没有配置虚拟机

####配置
PS:我这边以安卓开发为主,IOS 后面补上
打开 Android Studio,到主页面打开 Plugins
Flutter基础填坑
搜索 Flutter
Flutter基础填坑
右边点击安装它即可
然后重启 Android Studio ,你可以看到菜单已经有了
Flutter基础填坑
点击它新建一个项目,这里会要填一些基础信息,按照需要的来即可
然后就进了 Android 主界面,这个时候进入工具栏的 Tools -> AVD Manager
Flutter基础填坑
在这边创建虚拟机,可以选择官方已经预设的几个机型,或者自己根据分辨率来配置
Flutter基础填坑
选择机型以后是选择操作系统,现在主流系统都是 派(9.0) 和 奥利奥(8.0)如果是显示了 Download则需要下载这个系统才能使用。
AVD 配置完成以后 开机 点击工具栏的 debug
Flutter基础填坑
虚拟机就会运行我们的 flutter app
Flutter基础填坑

#####在 vscode 中开发
Android Studio 把我的 8G 内存小水管撑满了,加上前端属性不是很喜欢这种重量级的 IDE,果断切换到 Vscode,索性 Vscode 对 Flutter 支持很棒
去插件中心安装 flutter
Flutter基础填坑
安装这个的时候会问你 dart 插件要不要一起安装,dart 是 flutter 的语言,所以也要一起安装。
这个时候你可以把 AVD 和 Android Studio 都关掉了 用 Vscode 打开创建的 flutter 项目 随便点开一个文件 可以看到右下角多了一栏
Flutter基础填坑
默认他是 No Device 点击它
Flutter基础填坑
如果之前你在 Android 里创建过虚拟机 这里会列出 没有你可与直接用他新建一个出来
点击即可开启虚拟机
然后直接项目里控制台flutter run
即可构建预览代码
Flutter基础填坑
这个时候 Flutter 会提示你 想要热更新的话按一下 R 就可以 这样的话保存热更新就不是很方便了 需要 ctrl+s 然后再去控制带 R 一下 那咋办呢?
flutter run --help 看一眼
Flutter基础填坑
尝试flutter run --hotflutter run --debug都不行 最后在stackoverflow上看到一个老哥说用 vscode 里的调试找到了方法
Flutter基础填坑
点开侧边栏的虫子 然后点击播放 就进入调试模式
这个时候代码就是热更新的 保存后延迟个一两秒就会更新(这个应该取决于个人电脑配置)

####标签使用
#####Text Widget

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'Text widget',
            home: Scaffold(
                body:Center(
                    child: Text(
                        'Hello Widget,马天宇卖啤酒卖啤酒卖啤酒,马天宇最后卖啤酒,马天宇卖啤酒卖啤酒卖啤酒,马天宇最后卖啤酒,马天宇卖啤酒卖啤酒卖啤酒,马天宇最后卖啤酒',
                        textAlign: TextAlign.left,
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                        style: TextStyle(
                            fontSize: 25.0,
                            color: Color.fromARGB(255, 255, 125, 125),
                            decoration: TextDecoration.underline,
                            decorationStyle: TextDecorationStyle.solid,
                        )
                    ),
                ),
            ),
        );
    }
}

样式总体像网页里的 css ,写法类似 jsx
Text 里第一个参数为内容,后面为样式,样式分为两类,组件样式和内容样式,组件样式直接写在内容后面,内容样式则写在 style: TextStyle 里在写一层。
#####Container Widget
Container组件类似网页中的 div 也就是盒模型

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'Text widget',
            home: Scaffold(
                body:Center(
                    child: Container(
                        child: new Text('clp clp clp',style:TextStyle(fontSize: 40.0)),
                        alignment: Alignment.topLeft,
                        width: 500.0,
                        height: 400.0,
                        // color: Colors.lightBlue,
                        // padding: const EdgeInsets.all(10.0),
                        padding: const EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 20.0),
                        margin: const EdgeInsets.all(60.0),
                        decoration: new BoxDecoration(
                            gradient: const LinearGradient(
                                colors: [Colors.lightBlue,Colors.greenAccent,Colors.purple]
                            ),
                            border: Border.all(width:2.0,color:Colors.red)
                        ),
                    )
                ),
            ),
        );
    }
}

部分属性也与网页中无异,需要注意的是alignment、padding、decoration
alignment指定内容的摆放位置,有 center/centerLeft/centerRight/topCenter/topLeft/topRight/bottomCenter/bottomLeft/bottomRight 这些属性 也十分的语义化
padding 的定义方式依靠定义一个常量 EdgeInsets ,他下面有两个常用的方法 allfromLTRB,前者类似网页中 padding:40px 这样一次性全部定义,而fromLTRB则是单独写左上右下这样的顺序的值,margin 也是同理。
decoration则是更高阶的装饰属性,类似上面直接在 Container()中写Colorflutter 认为这是一个在构造函数中声明的简写,而 decoration 中可以做到更加规范和详细的设定,如上 我们先声明了一个BoxDecoration盒模型装饰,定义了他的渐变gradientgradient是一个常量LinearGradient,依靠数组构成。border 的定义则跟 padding 类似,使用 all 或者 fromLTRB来写,并在里面声明宽度和颜色。
#####Image
导入图片有四种方式
- asset - 项目包
- file - 设备本地
- memory - 内存(Uint8List资源图片)
- network - 网络

基于容器填充图片有六种模式
- contain - 保持比例并尽量填充
- fill - 强制拉伸填充
- fitWidth - 保持横向填充满 纵向裁切或留空
- fitHeight - 保持纵向填充满 横向裁切或留空
- cover - 图片不变形 但被裁切
- scaleDown - 图片大小不改变
图片混合(让图片改变颜色)

child:new Image.network(
  'https://www.hansuku.com/wp-content/themes/Lover/images/thumbs/8.jpg,
    color: Colors.greenAccent, //要混合的颜色
    colorBlendMode: BlendMode.darken, //混合模式
),

重复

repeat: ImageRepeat.repeatX

重复有四个选项
- ImageRepeat.noRepeat - 不重复(默认)
- ImageRepeat.repeat - X 轴和 Y 轴都重复
- ImageRepeat.repeatX - X轴重复
- ImageRepeat.repeatY - Y轴重复
以上代码整体

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'Text widget',
            home: Scaffold(
                body:Center(
                    child: Container(
                        child:new Image.network(
                            'https://www.hansuku.com/wp-content/themes/Lover/images/thumbs/8.jpg',
                            // fit: BoxFit.contain,//保持比例并尽量填充
                            // fit: BoxFit.fill,//强制拉伸填充
                            // fit: BoxFit.fitWidth,//保持横向填充满 纵向裁切或留空
                            // fit: BoxFit.fitHeight,//保持纵向填充满 横向裁切或留空
                            // fit: BoxFit.cover,//图片不变形 但被裁切
                            fit: BoxFit.scaleDown,//图片大小不改变
                            color: Colors.greenAccent,
                            colorBlendMode: BlendMode.darken,
                            repeat: ImageRepeat.repeatX,
                        ),
                        width: 300.0,
                        height: 200.00,
                        color: Colors.lightBlue,
                    ),
                ),
            ),
        );
    }
}

#####ListView 列表
列表算是最常见的布局之一了 flutter 的列表也简单易懂

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: '马老师是个体面人',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('ListView Widget')
                ),
                body: new ListView(
                    children: <Widget>[
                        new ListTile(//列表瓦片
                            leading: new Icon(Icons.access_time),
                            title: new Text('access_time')
                        ),
                        new ListTile(//列表瓦片
                            leading: new Icon(Icons.access_time),
                            title: new Text('access_time')
                        ),
                        new ListTile(//列表瓦片
                            leading: new Icon(Icons.access_time),
                            title: new Text('access_time')
                        )
                    ],
                )
            ),
        );
    }
}

横向滚动

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: '马老师是个体面人',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马天宇是个体面人')
                ),
                body: Center(
                    child: Container(
                        height: 200.0,
                        child: new ListView(
                            scrollDirection: Axis.horizontal,
                            children: <Widget>[
                                new Container(
                                    width: 180.0,
                                    color: Colors.lightBlue
                                ),
                                new Container(
                                    width: 180.0,
                                    color: Colors.amber
                                ),
                                new Container(
                                    width: 180.0,
                                    color: Colors.deepOrange
                                ),
                                new Container(
                                    width: 180.0,
                                    color: Colors.deepPurpleAccent
                                )
                            ],
                        ),
                    ),
                )
            ),
        );
    }
}

#####动态数据
dart中有一个类型为List,可以看作是JS中的数组
他有几种声明方式
- myList = List(): 非固定长度的声明。
- myList = List(2): 固定长度的声明。
- myList= List<String>():固定类型的声明方式。
- myList = [1,2,3]: 对List直接赋值。

import 'package:flutter/material.dart';

void main () => runApp(MyApp(
    items: new List<String>.generate(1000, (i)=>"Item $i")
    //generate是一个方法 用于生产数组中的元素 产生一个带值的 list 变量
));

class MyApp extends StatelessWidget{
    //接收上面的参数
    final List<String> items;
    MyApp({Key key, @required this.items}):super(key:key);
    // 这里是一个构造函数 除了 key 为必传 我们还增加了一个参数 @required 的意思就是必传 :super如果父类没有无名无参数的默认构造函数,则子类必须手动调用一个父类构造函数
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: '马老师是个体面人',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马天宇是个体面人')
                ),
                //使用ListView.builder动态列表
                body: new ListView.builder(
                    itemCount: items.length,
                    itemBuilder: (context , index){
                        return new ListTile(
                            title: new Text('${items[index]}'),
                        );
                    }
                )
            ),
        );
    }
}

#####网格列表
这里先创建一个文字的网格列表
padding跟上面的一样,
crossAxisSpacing是网格间的空当,相当于每个网格的间距
crossAxisCount是网格的列数,相当于一行放置的网格数量

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: '马老师是个体面人',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马天宇是个体面人')
                ),
                body: GridView.count(
                    padding: const EdgeInsets.all(20.0),
                    crossAxisSpacing: 10.0,
                    crossAxisCount: 3,
                    children: <Widget>[
                        const Text('Hey Black Man'),
                        const Text('Hey Ma Guapi'),
                        const Text('hansuku.com'),
                        const Text('马天宇女装大佬'),
                        const Text('今晚打老虎'),
                        const Text('月光光照大床'),
                    ],
                )
            ),
        );
    }
}

图片布局
这里我们把样式参数都丢到gridDelegate里 这里类似于一个 grid 的构造函数
- mainAxisSpacing横轴上的每个项目之间的逻辑像素
- childAspectRatio宽高比 值为宽是高的多少倍 如果宽是高的2倍,则为2.0,如果高是宽的2倍 则写0.5

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: '马老师是个体面人',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马天宇是个体面人')
                ),
                body: GridView(
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisSpacing: 2.0,
                        mainAxisSpacing: 2.0,
                        childAspectRatio: 0.7,
                        crossAxisCount: 3,
                    ),

                    children: <Widget>[
                        new Image.network('http://img5.mtime.cn/mt/2018/10/22/104316.77318635_180X260X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/10/10/112514.30587089_180X260X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/13/093605.61422332_180X260X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/07/092515.55805319_180X260X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/21/090246.16772408_135X190X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/17/162028.94879602_135X190X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/19/165350.52237320_135X190X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/16/115256.24365160_180X260X4.jpg',fit: BoxFit.cover),
                        new Image.network('http://img5.mtime.cn/mt/2018/11/20/141608.71613590_135X190X4.jpg',fit: BoxFit.cover),
                    ],
                )
            ),
        );
    }
}

#####Row控件(水平布局)
Row控件可以分为灵活排列和非灵活排列两种,这两种模式都需要熟练掌握,等经验丰富后可根据需求进行使用
######非灵活排列
顾名思义 他是一行内最基本的排列,假设我们制造三个按钮出来,如果子元素不足一行 他会留有空隙,如果子元素超出,则会警告

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: new Row(
                    children: <Widget>[
                        new RaisedButton(
                            onPressed: (){

                            },
                            color: Colors.redAccent,
                            child: new Text('红色按钮'),
                        ),
                        new RaisedButton(
                            onPressed: (){

                            },
                            color: Colors.orangeAccent,
                            child: new Text('黄色按钮'),
                        ),
                        new RaisedButton(
                            onPressed: (){

                            },
                            color: Colors.pinkAccent,
                            child: new Text('粉色按钮'),
                        )
                    ],
                )
            )
        );
    }
}

######灵活排列
这样元素会自动填充满一行

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: new Row(
                    children: <Widget>[
                        Expanded(
                            child: new RaisedButton(
                                onPressed: (){

                                },
                                color: Colors.redAccent,
                                child: new Text('红色按钮'),
                            ),
                        ),
                        Expanded(
                            child: new RaisedButton(
                                onPressed: (){

                                },
                                color: Colors.orangeAccent,
                                child: new Text('黄色按钮'),
                            ),
                        ),
                        Expanded(
                            child: new RaisedButton(
                                onPressed: (){

                                },
                                color: Colors.pinkAccent,
                                child: new Text('粉色按钮'),
                            ) ,
                        )
                    ],
                )
            )
        );
    }
}

######灵活不灵活混用
如果我们想中间一个按钮大 旁边两个按钮小 就可以用到混用

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: new Row(
                    children: <Widget>[
                        new RaisedButton(
                            onPressed: (){

                            },
                            color: Colors.redAccent,
                            child: new Text('红色按钮'),
                        ),
                        Expanded(
                            child: new RaisedButton(
                                onPressed: (){

                                },
                                color: Colors.orangeAccent,
                                child: new Text('黄色按钮'),
                            ),
                        ),
                        new RaisedButton(
                            onPressed: (){

                            },
                            color: Colors.redAccent,
                            child: new Text('红色按钮'),
                        ),
                    ],
                )
            )
        );
    }
}

#####垂直布局Column组件
首先Text演示

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: Column(
                    children: <Widget>[
                        Text('I am Hansuku'),
                        Text('My Website is hansuku.com'),
                        Text('I love coding')
                    ],
                )
            )
        );
    }
}

这个时候会以最长的‘My Website is hansuku.com’为中心 第一行第三行做垂直居中 这样的效果并不好看
通过设置crossAxisAlignment来调整对齐方向
crossAxisAlignment: CrossAxisAlignment.start
这样文字是靠左对齐
#####主轴和副轴的辨识
对齐方式中有分主轴mainAxisAlignment和副轴crossAxisAlignment,他们的对应方法是:
- 如果是 Column 组件 垂直方向为主轴 水平方向为副轴
- 如果是 Row 组件 水平方向为主轴 垂直方向为副轴
首先让上面三段文字在屏幕中垂直方向居中

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                        Text('I am Hansuku'),
                        Text('My Website is hansuku.com'),
                        Text('I love coding')
                    ],
                )
            )
        );
    }
}

如果想要这三段文字在屏幕中水平居中 那么需要使用Center组件

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                        Center(child: Text('I am Hansuku')),
                        Center(child: Text('My Website is hansuku.com'),),
                        Center(child: Text('I love coding'))
                    ],
                )
            )
        );
    }
}

######Expanded属性的使用
结合灵活布局 假设我们想让中间区域变大 那么只需要把第二个Center组件换成Expanded组件

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('马冬梅'),
                ),
                body: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                        Center(child: Text('I am Hansuku')),
                        Expanded(child: Center(child: Text('My Website is hansuku.com'))),
                        Center(child: Text('I love coding'))
                    ],
                )
            )
        );
    }
}

#####Stack层叠布局
水平布局和垂直布局基本上可以应付常见的布局 但是想要实现类似网页里的position绝对定位 则需要用到Stack叠层布局
######CircleAvatar头像组件

new CircleAvatar(
    backgroundImage: new NetworkImage('https://www.hansuku.com/wp-content/themes/Lover/images/thumbs/7.jpg'),
    radius: 100.0,
)

CircleAvatar是一个专门用来做头像的组件,backgroundImage不必多说,radius也与 css 中指定圆角是一样的功效。

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        var stack = new Stack(
            alignment: const FractionalOffset(0.5, 0.8),
            children: <Widget>[
                new CircleAvatar(
                    backgroundImage: new NetworkImage('https://www.hansuku.com/wp-content/themes/Lover/images/thumbs/7.jpg'),
                    radius: 100.0,
                ),
                new Container(
                    decoration: new BoxDecoration(
                        color: Colors.lightBlue,
                    ),
                    padding: EdgeInsets.all(5.0),
                    child: new Text('boom'),
                )
            ],
        );
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('垂直方向布局'),
                ),
                body: Center(child: stack),
            )
        );
    }
}

这样可以制作出图像在底部,文字悬浮于图像之上的效果。
######StackPositioned属性
假设我们需要在图片上放两个文字 并且可以指定位置 就可以使用Positioned来完成

import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        var stack = new Stack(
            alignment: const FractionalOffset(0.5, 0.8),
            children: <Widget>[
                new CircleAvatar(
                    backgroundImage: new NetworkImage('https://www.hansuku.com/wp-content/themes/Lover/images/thumbs/7.jpg'),
                    radius: 100.0,
                ),
                new Positioned(
                    top: 10.0,
                    left: 10.0,
                    child: new Text('喵喵喵'),
                ),
                new Positioned(
                    bottom: 10.0,
                    right: 10.0,
                    child: new Text('汪汪汪'),
                )
            ],
        );

        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('垂直方向布局'),
                ),
                body: Center(child: stack),
            )
        );
    }
}
import 'package:flutter/material.dart';

void main () => runApp(MyApp());

class MyApp extends StatelessWidget{
    @override
    Widget build(BuildContext context){
        var card = new Card(
            child: Column(
                children: <Widget>[
                    ListTile(
                        title: new Text('浙江省杭州市江干区',style: TextStyle(fontWeight: FontWeight.w500)),
                        subtitle: new Text('Hansuku: 13511111118'),
                        leading: new Icon(Icons.account_box,color: Colors.lightBlue),
                    ),
                    new Divider(),
                    ListTile(
                        title: new Text('江西省赣州市',style: TextStyle(fontWeight: FontWeight.w500)),
                        subtitle: new Text('马老师:18111111111'),
                        leading: new Icon(Icons.account_box,color: Colors.lightBlue),
                    ),
                    new Divider(),
                    ListTile(
                        title: new Text('江西省南昌市',style: TextStyle(fontWeight: FontWeight.w500)),
                        subtitle: new Text('马老爷:18111111111'),
                        leading: new Icon(Icons.account_box,color: Colors.lightBlue),
                    ),
                ],
            ),
        );
        return MaterialApp(
            title: 'ListView widget',
            home: Scaffold(
                appBar: new AppBar(
                    title: new Text('垂直方向布局'),
                ),
                body: Center(child: card)
            )
        );
    }
}

上面有几个注意的点 new Divider()是一条分割线,Card会有一个自带的阴影效果
#####一般页面及导航

import 'package:flutter/material.dart';
void main(){
  runApp(MaterialApp(
    title:'导航演示1',
    //定义第一个屏幕为 FirstScreen
    home:new FirstScreen()
  ));
}
//写第一个屏幕的内容
class FirstScreen extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return new Scaffold(
      appBar: AppBar(title:Text('导航页面')),
      body:Center(
        child:RaisedButton(
          child:Text('查看商品详情页面'),
          //按钮点击事件
          onPressed: (){
            Navigator.push(context,new  MaterialPageRoute(
              builder:(context) =>new SecondScreen())
            );
          },
        )
      )
    );
  }
}
//第二个页面的内容
class SecondScreen extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return Scaffold(
      appBar:AppBar(title:Text('商品详情页')),
      body:Center(child:RaisedButton(
        child:RaisedButton(
          child:Text('返回'),
          //按钮点击事件
          onPressed: (){
            Navigator.pop(context);
          },
        )
      ))
    );
  }
}

#####导航传参
首先用类来声明一个数据结构

class Product{
    final String title;
    final String description;
    Product(this.title,this.description);
}

然后我们写一个商品列表

void main(){
    runApp(MaterialApp(
        title: '导航传参',
        home: ProductList(
            products: List.generate(20, 
                (i) => Product('商品 $i','这是一个商品详情,编号为$i')
            )
        )
    ));
}

class ProductList extends StatelessWidget {
    final List<Product> products;
    ProductList({Key key,@required this.products}):super(key:key);

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: Text('商品列表')),
            body: ListView.builder(
                itemCount: products.length,
                itemBuilder: (context , index){
                    return ListTile(
                        title: Text(products[index].title),
                        onTap: (){
                            Navigator.push(context, MaterialPageRoute(
                                builder: (context) => new ProductDetail(product: products[index])
                            ));
                        },
                    );
                },
            )
        );
    }
}

这里注意一点是我们在这里传递参数的,数据是使用List.generate生成的

    home: ProductList(
        products: List.generate(20, 
            (i) => Product('商品 $i','这是一个商品详情,编号为$i')
        )
    )

然后是点击每个项目的事件

onTap: (){
    Navigator.push(context, MaterialPageRoute(
        builder: (context) => new ProductDetail(product: products[index])
    ));
},
Responses