代码改变世界

Flutter移动前端

2019-11-26 17:43  小罗世界  阅读(1185)  评论(0)    收藏  举报

一、flutter基础

 1、flutter介绍 

    Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

  2、flutter特点: 

  • **跨平台:**现在Flutter至少可以跨4种平台,甚至支持嵌入式开发。我们常用的有Linux、Android、IOS,甚至可以在谷歌最新的操作系统上Fuchsia进行运行,经过第三方扩展,甚至可以跑在MacOS和Windows上,到目前为止,Flutter算是支持平台最多的框架了,良好的跨平台性,直接带来的好处就是减少开发成本。
  • 原生用户界面: 它是原生的,让我们的体验更好,性能更好。用官方的话讲就是平滑而自然的滑动效果和平台感知,为您的用户带来全新的体验。(可以看一下图片,这是Flutter的表现)
  • **开源免费:**这个不用多说,我们只要学会并使用,这些都是免费的。这对于大公司是非常必要的,有人说你可以用破解版什么的....说明你还是小公司,我们公司的软件全部是正版,就更不用说操作系统和生产环境了,否则各种公司的侵权官司你都解决不了。

二、Flutter的开发环境搭建widows版

  1,系统条件要求: 

  • **操作系统:**必须windows7以上64位操作系统。(这个一般都能很好的满足)
  • **磁盘空间:**大于3个G,虽然官方说的是400M,但是你还需要安装Android Studio 和 虚拟机,所以至少要3个G左右,如果能达到5个G就更好了(满足多个虚拟机的要求)。
  • 需要Git环境:Flutter需要git环境的支持,所以这个也要有,作为一个前端,这个是必备工具,所以我在文章中就不教大家安装了。

  2、Java环境的安装

     既然要做原生应用了,而且是基于Android的,那还是需要我们安装一下JAVA的环境的,我比一般得到一个新系统后首先做的就是这一步。这个就相当于你按一个软件,你不用考虑太多。

https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

这个地址会随着Java升级有所变化,如果已经改变了,请百度搜索java下载或者直接到Java官网下载。
3flutter sdk的安装
  a、 去官网下载flutter安装包,将安装包zip解压到你想安装Flutter SDK的路径
(如: E:\fluter\flutter;注意,不要将flutter安装到需要一些高权限的路径如C:\Program Files\,这个没必要跟我一样,凭借自己喜好设置就好)。
  b、 在Flutter安装目录的flutter文件下找到flutter_console.bat,双击运行并启动flutter命令行,接下来,你就可以在Flutter命令行运行flutter命令了。
  c、 配置环境变量,复制安装flutter目录下的bin目录作为配置环境变量的路径,
 4、验证flutter测试:
    用flutter doctor命令进行测试有以下几种情况:

  C:\Users\Administrator>flutter doctor
    Doctor summary (to see all details, run flutter doctor -v):
      [√] Flutter (Channel stable, v1.9.1+hotfix.6, on Microsoft Windows [Version 10.0.18362.418], locale zh-CN)

      [√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
      [√] Android Studio (version 3.5)
      [√] Connected device (1 available)

  要全部是打勾才可以用;假如Android Studio是打叉那需要下载Android Studio,若Connected device是感叹号,那需要在Android studio中tools中点击avd安装虚拟机,

 

5、安装Android Studio:

  下载Android Studio:直接到官网进行下载就可以了。下载地址:https://developer.android.com/进入后向下拉,然后看到如下界面,点击红圈处进行下载。 

  安装Android Studio 软件:这个安装也就是差不多下一步下一步,如果你真的不会,给你个比较详细的教程。https://www.cnblogs.com/xiadewang/p/7820377.html

  打开Android Stuido 软件,然后找到Plugin的配置,搜索Flutter插件。

  出现上图,点中间的Search in repositories,然后点击安装。 

  安装完成后,你需要重新启动一下Android Studio软件

6、安装Android证书

  安装好Android Studio后,再次打开终端(命令行),输入flutter doctor,这时候的x会明显减少,但是你还是会遇到1-2个,其中有一个就是提示没有安装证书。安装证书只要在终端里执行下面的命令。

flutter doctor --android-licenses
然后会提示你选Y/N,不要犹豫,一律选择Y,就可以把证书安装好。(说的都是一大堆一大堆的英文,我也看不懂是啥)

三、flutter的基础用法
基础组件:
Center(居中布局),Container(相当于div),MaterialApp(材料布局App,基本上都用)
Scaffold(脚手组件布局)
AppBar(导航栏)
context:(上下文)
build函数是创建上下文的

Widget build(BuildContext context)
1、第一个的程序,编写一个hello world
import 'package:flutter/material.dart';//导入flutter包

void main() => runApp(new MyApp());//创建类函数

class MyApp extends StatelessWidget{//创建的函数继承于StatelessWidget,StatelessWidget是没有形状的类
@override//重构函数
Widget build(BuildContext context){ //建立组件,flutter中一切皆是组件
return MaterialApp(//返回组件app
title: 'welcome to flutter', //app名字
home: Scaffold( //组件布局Scaffold,全部都要在在这个Scaffold中编写代码
appBar: AppBar( //页面上的导航条,相当于web中的head(头部)
title: Text('welcome to flutter'), //导航条中的名字
),
body: Center( //主要身体部分
child: Text('hello world'), //center中的属性,text
),
),
);

}
}

2,Text组件

text组件是用于编辑文字,属性如下:

1)、textAlign:是用于编辑字体对齐方式

     textAlign: TextAlign.start,//相当于左对齐
//                 textAlign: TextAlign.left,//左对齐
//                 textAlign: TextAlign.right,//右对齐
//                 textAlign: TextAlign.end,//右对齐
                 textAlign: TextAlign.center,//居中

2)、maxLines:由于显示页面能显示几行,值为多少就显示多少,

maxLines: 1 ,//显示限度最大行数,值只能是数字,让后随便设置数字

3)、overflow:文字溢出,

  overflow: TextOverflow.clip,//字体溢出,后面多余的直接舍掉或者不显示(切掉)
           overflow: TextOverflow.ellipsis,//字体溢出,后面多余部分用三个点(表示省略)常用
//           overflow: TextOverflow.fade,//表示字体从上到下显示到透明(隐隐约约)
//           overflow: TextOverflow.visible//

4)、style:用于样式,字体样式TextStyle

fontSize:字体大小

color:字体颜色,注意Color.fromARGB(a,r,g,b)  a代表透明度(0-255),rgb代表红绿蓝

decoration:表示下划线,具体如下代码

style: TextStyle(
           fontSize: 20.0,//字体大小设置
           color: Color.fromARGB(200, 255, 0, 0),//a代表透明度(0-255),rgb代表红绿蓝
           decoration: TextDecoration.underline,//下划线
//           decorationStyle: TextDecorationStyle.dashed,//矩形虚线
//           decorationStyle: TextDecorationStyle.solid,//实线,默认
           decorationStyle: TextDecorationStyle.dotted,//小虚线
         ),
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main(){
  runApp(YouApp());
}
class YouApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
   return MaterialApp(
     title: 'welcome to flutter',
     home: Scaffold(
       appBar: AppBar(
         title: Text('flutter'),
       ),//手机上第一栏导航条
       body: Center(
         child: Text(
             'hello,我是哈哈哈,第一学习次flutter前端,这对于我来说是一门新的语言,所以我愿意把我所有的精力都投入在里面,我希望我越来越流弊',
//                 textAlign: TextAlign.start,//相当于左对齐
//                 textAlign: TextAlign.left,//左对齐
//                 textAlign: TextAlign.right,//右对齐
//                 textAlign: TextAlign.end,//右对齐
                 textAlign: TextAlign.center,//居中
           maxLines: 1 ,//显示限度最大行数,值只能是数字,让后随便设置数字
//           overflow: TextOverflow.clip,//字体溢出,后面多余的直接舍掉或者不显示(切掉)
           overflow: TextOverflow.ellipsis,//字体溢出,后面多余部分用三个点(表示省略)常用
//           overflow: TextOverflow.fade,//表示字体从上到下显示到透明(隐隐约约)
//           overflow: TextOverflow.visible//
         style: TextStyle(
           fontSize: 20.0,//字体大小设置
           color: Color.fromARGB(200, 255, 0, 0),//a代表透明度(0-255),rgb代表红绿蓝
           decoration: TextDecoration.underline,//下划线
//           decorationStyle: TextDecorationStyle.dashed,//矩形虚线
//           decorationStyle: TextDecorationStyle.solid,//实线,默认
           decorationStyle: TextDecorationStyle.dotted,//小虚线
         ),

         ),
       ),
     ),
   );
  }
}
字体组件中的属性

补充: subtitle: Text('this is a subtitle', style: TextStyle(fontWeight: FontWeight.bold),),//副标题,字体加粗

3、container组件

container相当于web前端的div

padding:内边距设置

//padding: const EdgeInsets.all(10.0),//表示上下左右都离边距10个像素

//padding: const EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 10.0),LTRB表示左(left)上(top)右(right)下(bottom),const表示设置常量关键字,其他注意语法(背)

 decoration: new BoxDecoration(//装饰器盒子
             gradient: const LinearGradient(//gradient界面,线性界面LinearGradient
                 colors: [Colors.lightBlue,Colors.lightGreen,Colors.limeAccent,Colors.lightBlue]),//添加颜色可以在里面加多或少
              border:Border.all(width:5.0,color: Colors.red),//添加边框
上一段代码表示,界面背景设置,背景颜色设置好看
  注意:color: Colors.lightBlue,
            //背景色一定要在color后面加上s

border:表示边框,具体如下代码
 body: Center(
          child: Container(
            //container相当于div
            child: Text(
              'helllo container',
              style: TextStyle(
                fontSize: 25,
                color: Color.fromARGB(100, 0, 0, 0),
                decoration: TextDecoration.underline,
                decorationColor: Color.fromARGB(100, 250, 0, 0),
                decorationStyle: TextDecorationStyle.solid,
              ),
            ),
//      alignment: Alignment.center,
//      alignment: Alignment.centerLeft, //中间左对齐
//      alignment Alignment.centerRight, //中间右对齐
            alignment: Alignment.topLeft,
            //上左对齐,topRight中间右对齐
//      alignment: Alignment.bottomRight, //下右对齐,bottomLeft下左d齐
            width: 400.0,
            height: 400.0,
//            color: Colors.lightBlue,
            //背景色一定要在color后面加上s
//        padding: const EdgeInsets.all(10.0),//表示上下左右都离边距10个像素
            padding: const EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 10.0),
            margin: const EdgeInsets.all(10.0), //边框里外界的距离
            decoration: new BoxDecoration(//装饰器盒子
             gradient: const LinearGradient(//gradient界面,线性界面LinearGradient
                 colors: [Colors.lightBlue,Colors.lightGreen,Colors.limeAccent,Colors.lightBlue]),//添加颜色可以在里面加多或少
              border:Border.all(width:5.0,color: Colors.red),//添加边框
            ),
          ),
        ),

 

具体内容见下代码练习:
import 'package:flutter/material.dart';

void main() => runApp(new YourApp());

class YourApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'welcome study container',
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            'welcome study container',
            textAlign: TextAlign.right,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(
                fontSize: 25,
                color: Color.fromARGB(255, 0, 0, 255),
                decoration: TextDecoration.lineThrough,
                decorationStyle: TextDecorationStyle.solid,
                decorationColor: Color.fromARGB(255, 200, 0, 0)),
          ),
        ),
        body: Center(
          child: Container(
            //container相当于div
            child: Text(
              'helllo container',
              style: TextStyle(
                fontSize: 25,
                color: Color.fromARGB(100, 0, 0, 0),
                decoration: TextDecoration.underline,
                decorationColor: Color.fromARGB(100, 250, 0, 0),
                decorationStyle: TextDecorationStyle.solid,
              ),
            ),
//      alignment: Alignment.center,
//      alignment: Alignment.centerLeft, //中间左对齐
//      alignment Alignment.centerRight, //中间右对齐
            alignment: Alignment.topLeft,
            //上左对齐,topRight中间右对齐
//      alignment: Alignment.bottomRight, //下右对齐,bottomLeft下左d齐
            width: 400.0,
            height: 400.0,
//            color: Colors.lightBlue,
            //背景色一定要在color后面加上s
//        padding: const EdgeInsets.all(10.0),//表示上下左右都离边距10个像素
            padding: const EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 10.0),
            margin: const EdgeInsets.all(10.0), //边框里外界的距离
            decoration: new BoxDecoration(//装饰器盒子
             gradient: const LinearGradient(//gradient界面,线性界面LinearGradient
                 colors: [Colors.lightBlue,Colors.lightGreen,Colors.limeAccent,Colors.lightBlue]),//添加颜色可以在里面加多或少
              border:Border.all(width:5.0,color: Colors.red),//添加边框
            ),
          ),
        ),
      ),
    );
  }
}
container练习

 4、Image组件

image属性是图片的插入和布局,

Image.network是在网上链接自己想要的图片

image.asset实在项目包里直接调用自己的图片

image.file是在在计算机上调用绝对路径

child: new Image.network(//从网络上的地址,常用
//          child: new Image.file()//绝对路径文件图片
//          child: new Image.asset()//从项目包里打开文件
                 'http://pic1.win4000.com/pic/9/35/e9babcbf13.jpg',)

对图片样式的修饰属性为  fit(填充),color(颜色),colorBlendMode(颜色混合属性,如黑白,复古),repeat(图片重复填充样式)

注意:混合属性要和颜色一起用才有混合效果。

样式意义如下:

 

fit:BoxFit.contain,) //不会处理,保留原图片的比例
//          fit:BoxFit.cover,)//不变形,但是图片被裁切了
//          fit:BoxFit.fitWidth ,),//横向填充
//          fit:BoxFit.fitHeight ,),//纵向填充
//          fit:BoxFit.scaleDown ,),//不会该表原图片的大小
          fit:BoxFit. fill,//填满宽
          color: Colors.lightBlue,//给图片加背景颜色,覆盖性的添加,若想看见图片,就必须加colorBlendMode混合属性一起用
            colorBlendMode: BlendMode.darken,//colorBlendMode混合属性,BlendMode有很多属性,这个要配合颜色来配合
//          repeat: ImageRepeat.repeatX,//横向重复
//          repeat: ImageRepeat.repeatY,//纵向重复
//          repeat: ImageRepeat.noRepeat,//不重复
          repeat: ImageRepeat.repeat,//重复

 

代码示例:

import'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
 Widget build(BuildContext context){
    return MaterialApp(
      title: 'app',
      home: Scaffold(
        appBar: AppBar(
          title: Text('image图片布局'),
        ),
        body:Container(
          alignment: Alignment.center,
          width:500.0,
          height: 600.0,
          padding: const EdgeInsets.all(10.0),
          margin: const EdgeInsets.all(5.0),
          decoration: BoxDecoration(
              border: Border.all(width: 2.0,color: Colors.black,style: BorderStyle.solid),
           gradient: const LinearGradient(
               colors:[Colors.lightBlue,Colors.lightGreen]),
          ),
          child: new Image.network(//从网络上的地址,常用
//          child: new Image.file()//绝对路径文件图片
//          child: new Image.asset()//从项目包里打开文件
                 'http://pic1.win4000.com/pic/9/35/e9babcbf13.jpg',
//          fit:BoxFit.contain,) //不会处理,保留原图片的比例
//          fit:BoxFit.cover,)//不变形,但是图片被裁切了
//          fit:BoxFit.fitWidth ,),//横向填充
//          fit:BoxFit.fitHeight ,),//纵向填充
//          fit:BoxFit.scaleDown ,),//不会该表原图片的大小
          fit:BoxFit. fill,//填满宽
          color: Colors.lightBlue,//给图片加背景颜色,覆盖性的添加,若想看见图片,就必须加colorBlendMode混合属性一起用
            colorBlendMode: BlendMode.darken,//colorBlendMode混合属性,BlendMode有很多属性,这个要配合颜色来配合
//          repeat: ImageRepeat.repeatX,//横向重复
//          repeat: ImageRepeat.repeatY,//纵向重复
//          repeat: ImageRepeat.noRepeat,//不重复
          repeat: ImageRepeat.repeat,//重复

          ),
        ),
      ),
    );
  }
}
代码示例

5、ListView Widget (列表组件)

leading:表示图标或这图片在文本之前显示

    new ListTile(
              leading: new Icon(Icons.access_alarm ),//flutter中的小图标,leading是在前面加小图标,在后面加的是trailing,见下代码
              title: Text('access_alarm'),//图标名
            ),
            
            //插入图片
            new ListTile(
              leading: CircleAvatar(   //圆形头像填充
                backgroundImage: NetworkImage('https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3120914462,2909377693&fm=26&gp=0.jpg'),//图片填充及来源
              ),
              title: Text('horse'),//标题
            ),

trailing:表示图片或者图标在文本之后显示

icon:表示图标

trailing: Icon(Icons.airline_seat_legroom_extra),//图标在挑剔后面不显示

示例代码如下:

示例代码

注意:一般列表默认是纵下列表(向下滑动的)

横向列表以及嵌套:

横向列表关键语句:scrollDirection: Axis.horizontal, //横向的列表初始化(horizontal)横向的意思

示例代码如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'luodehua DemoApp',
      home: Scaffold(
        appBar: AppBar(
          title: Text('ListView2横向'),
        ),
        body: Center(
          child: Container(
            height: 200,
            child: new ListView(//MyList就是继承ListView,在下一段调用
              scrollDirection: Axis.horizontal,//横向的列表初始化(horizontal)横向的意思
              children: <Widget>[
                new Container(
                  width: 100.0,
                  height: 50.0,
                  child: new Text('one', textAlign:TextAlign.center,),
                  color: Colors.red,
                ),
                new Container(
                  width: 100.0,
                  height: 50.0,
                  child: new Text('two', textAlign:TextAlign.center,),
                  color: Colors.blue,
                ),
                new Container(
                  width: 100.0,
                  height: 50.0,
                  child: new Text('three', textAlign:TextAlign.center,),
                  color: Colors.yellow,
                ),
                new Container(
                  width: 200.0,
                  height: 50.0,
                  child: new Text('four',
                    textAlign:TextAlign.center,
                    style: TextStyle(color: Colors.red,),),
                  color: Colors.black,
                ),
              ],
                ),
          ),
        ),
      ),
    );
  }
}
没嵌套

与没嵌套对比:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'luodehua DemoApp',
      home: Scaffold(
        appBar: AppBar(
          title: Text('ListView2横向'),
        ),
        body: Center(
          child: Container(
            height: 200,
            child: new MyList(//MyList就是继承ListView,在下一段调用
//              scrollDirection: Axis.horizontal,//横向的列表初始化(horizontal)横向的意思
//              children: <Widget>[
//                new Container(
//                  width: 100.0,
//                  height: 50.0,
//                  child: new Text('one', textAlign:TextAlign.center,),
//                  color: Colors.red,
//                ),
//                new Container(
//                  width: 100.0,
//                  height: 50.0,
//                  child: new Text('two', textAlign:TextAlign.center,),
//                  color: Colors.blue,
//                ),
//                new Container(
//                  width: 100.0,
//                  height: 50.0,
//                  child: new Text('three', textAlign:TextAlign.center,),
//                  color: Colors.yellow,
//                ),
//                new Container(
//                  width: 200.0,
//                  height: 50.0,
//                  child: new Text('four',
//                    textAlign:TextAlign.center,
//                    style: TextStyle(color: Colors.red,),),
//                  color: Colors.black,
//                ),
//              ],
                ),
          ),
        ),
      ),
    );
  }
}

//利用嵌套
class MyList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return ListView(
      scrollDirection: Axis.horizontal, //横向的列表初始化(horizontal)横向的意思
      children: <Widget>[
        new Container(
          width: 100.0,
          height: 50.0,
          child: new Text(
            '1',
            textAlign: TextAlign.center,
          ),
          color: Colors.red,
        ),
        new Container(
          width: 100.0,
          height: 50.0,
          child: new Text(
            '2',
            textAlign: TextAlign.center,
          ),
          color: Colors.blue,
        ),
        new Container(
          width: 100.0,
          height: 50.0,
          child: new Text(
            '3',
            textAlign: TextAlign.center,
          ),
          color: Colors.yellow,
        ),
        new Container(
          width: 200.0,
          height: 50.0,
          child: new Text(
            '4',
            textAlign: TextAlign.center,
            style: TextStyle(
              color: Colors.red,
            ),
          ),
          color: Colors.black,
        ),
      ],
    );
  }
}
嵌套调用

难度较大部分列表动态传参:

代码如下:需学习

 

import 'package:flutter/material.dart';

void main()=>runApp(MyApp(
  items: new List<String>.generate(100, (i)=>'Item $i')//传进去的动态参数,为字符串类型,generate(意思是生成100个,后面为命名函数(自定义))
//    List<String>.generate(length,generator)//length为要传的长度,generator是命名函数
));
class MyApp extends StatelessWidget{
  final List<String> items;//items是要传的参数,形参
  MyApp({Key key,@required this.items}):super(key:key);//this.items是上面items,@required表示参数是必须传的,super继承
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ListView Widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('welcome study ListView'),
        ),
        body:ListView.builder(itemCount: items.length,//builder是动态传参,length为上面的长度100
        itemBuilder: (context,index){
          return new ListTile(
            title: new Text('${items[index]}'),//传的实参写法
          );
        },),
      ),
    );
  }
}

 这是构造函数传参进去

 MyApp({Key key,@required this.items}):super(key:key);//主函数传参进去接受参数

数据是我们用List.generate生成
接受数据后用ListView.builder方法,作了一个根据传递参数数据形成的动态列表。

 

 6、网格列表组件(gridView widget)

网格组件用于较多于相册布局,

 属性: 

crossAxisSpacing: 2.0,//横轴网格之间的空格
mainAxisSpacing:2.0,//纵轴网格之间的距离
crossAxisCount: 3,//每一行显示多少列
SliverGridDelegateWithFixedCrossAxisCount(用于固定列数的场景)
SliverGridDelegateWithMaxCrossAxisExtent:用于子元素有最大宽度限制的场景;
childAspectRatio:1,//childAspectRatio(宽高比例,值为2时相当于宽是高的2倍)

用两种方法分别写:
第一种传统写法:
 body: GridView.count(
          padding: const EdgeInsets.all(2.0),
          crossAxisSpacing: 2.0,//横轴网格之间的空格
          mainAxisSpacing:2.0,//纵轴网格之间的距离
          crossAxisCount: 3,//每一行显示多少列
          children: <Widget>[
            new Image.network('http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg'),
            new Image.network('http://b-ssl.duitang.com/uploads/item/201208/30/20120830173930_PBfJE.jpeg'),
            new Image.network('http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg'),
            new Image.network('http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg'),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
          ],

第二种写法:

body: GridView(
        gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(     //gridDelegate如何控制排列子元素的一个委托,SliverGridDelegateWithFixedCrossAxisCount(用于固定列数的场景)
         //SliverGridDelegateWithFixedCrossAxisCount(用于固定列数的场景)
          //SliverGridDelegateWithMaxCrossAxisExtent:用于子元素有最大宽度限制的场景;
          //crossAxisCount:列数,即一行有几个子元素;
          //mainAxisSpacing:主轴方向上的空隙间距;
          //crossAxisSpacing:次轴方向上的空隙间距;
          //childAspectRatio:子元素的宽高比例。
          crossAxisCount: 3,
          crossAxisSpacing: 2.0,
          mainAxisSpacing: 2.0,
            childAspectRatio:1,//childAspectRatio(宽高比例,值为2时相当于宽是高的2倍)
        ) ,
        children: <Widget>[
          new Image.network('http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg',fit: BoxFit.cover),
            new Image.network('http://b-ssl.duitang.com/uploads/item/201208/30/20120830173930_PBfJE.jpeg',fit: BoxFit.cover),
            new Image.network('http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg',fit: BoxFit.cover),
            new Image.network('http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
        ],
        ),

这两种写法都可以,主要看你个人习惯爱好,

完整代码示例(以图片相册为例)

//网格列表
import 'package:flutter/material.dart';

void main()=>runApp(YourApp());
class YourApp extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'GridView',
      home: Scaffold(
        appBar: AppBar(
          title: Text('welcome study GridView'),
        ),
//        body: GridView.count(
//          padding: const EdgeInsets.all(2.0),
//          crossAxisSpacing: 2.0,//横轴网格之间的空格
//          mainAxisSpacing:2.0,//纵轴网格之间的距离
//          crossAxisCount: 3,//每一行显示多少列
//          children: <Widget>[
//            new Image.network('http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg'),
//            new Image.network('http://b-ssl.duitang.com/uploads/item/201208/30/20120830173930_PBfJE.jpeg'),
//            new Image.network('http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg'),
//            new Image.network('http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg'),
//            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
//            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
//            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
//            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
//            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg'),
//          ],
      body: GridView(
        gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(     //gridDelegate如何控制排列子元素的一个委托,SliverGridDelegateWithFixedCrossAxisCount(用于固定列数的场景)
         //SliverGridDelegateWithFixedCrossAxisCount(用于固定列数的场景)
          //SliverGridDelegateWithMaxCrossAxisExtent:用于子元素有最大宽度限制的场景;
          //crossAxisCount:列数,即一行有几个子元素;
          //mainAxisSpacing:主轴方向上的空隙间距;
          //crossAxisSpacing:次轴方向上的空隙间距;
          //childAspectRatio:子元素的宽高比例。
          crossAxisCount: 3,
          crossAxisSpacing: 2.0,
          mainAxisSpacing: 2.0,
            childAspectRatio:1,//childAspectRatio(宽高比例,值为2时相当于宽是高的2倍)
        ) ,
        children: <Widget>[
          new Image.network('http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg',fit: BoxFit.cover),
            new Image.network('http://b-ssl.duitang.com/uploads/item/201208/30/20120830173930_PBfJE.jpeg',fit: BoxFit.cover),
            new Image.network('http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg',fit: BoxFit.cover),
            new Image.network('http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
            new Image.network('http://img.52z.com/upload/news/image/20180621/20180621055734_59936.jpg',fit: BoxFit.cover),
        ],
        ),
      ),
    );
  }
}
完整代码

7、stack widget(层叠组件)

层叠就是把几个组件叠在一起,主要属性

alingnment属性是

alignment: FractionalOffset(0.5, 0.8), //里面参数为x轴,y轴,参数值范围时0~1,相对与Widget

 代码示例:

//stack层叠组件
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //放在build函数中定义变量

    var stack = Stack( //用变量代表组件,下面直接调用变量即可。
      alignment: FractionalOffset(0.5, 0.8), //里面参数为x轴,y轴,参数值范围时0~1,相对与Widget
      children: <Widget>[
        new CircleAvatar(
          radius: 100.0, //圆形形状百分之百
          backgroundImage: new NetworkImage(
            'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=745669936,3962756491&fm=26&gp=0.jpg',),
        ),
        new Container(
          decoration: BoxDecoration(
            border: Border.all(
                width: 2.0, color: Colors.red, style: BorderStyle.solid),
            color: Colors.lightBlue,
          ),
          padding: const EdgeInsets.all(10.0),
          child: Text('我好看'),
        ),
      ],
    );


    // TODO: implement build
    return MaterialApp(
      title: 'Column widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Column widget'),
        ),
        body: Center(
          //直接调用stack变量。
          child: stack,
        ),
      ),
    );
  }
}
View Code

8、positioned widget(位置组件)

属性就是:

left:左

top:上

bottom:下

right:右

可根据这写属性调组件的位置布局。

//positioned位置布局
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var stack = Stack(
//      alignment: FractionalOffset(0.5 ,0.1),

      children: <Widget>[
        new CircleAvatar(
          radius: 100.0,
          backgroundImage: NetworkImage(
              'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=745669936,3962756491&fm=26&gp=0.jpg'),
        ),
        new Positioned(
          left: 70,
          top: 110,
          child: MyContainer(),
        ),
        new Positioned(//位置布局
          child: MyText(),
          left: 50.0,
          top: 150.0,
        )
      ],
    );

    return MaterialApp(
      title: 'Positioned Widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Position study'),
        ),
        body: Center(
          child: stack,
        ),
      ),
    );
  }
}

class MyContainer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      padding: const EdgeInsets.all(10.0),
      child: Text(
        '我好看',
        style: TextStyle(
          color: Colors.red,
          fontWeight: FontWeight.bold,
        ),
      ),
      decoration: BoxDecoration(
        color: Colors.lightGreen,
      ),
    );
  }
}

class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Text(
      '加微信聊天',
      style: TextStyle(
          fontSize: 20.0,
          fontWeight: FontWeight.bold,
          fontFamily: 'yahei',
          color: Colors.blue),
    );
  }
}
View Code

9、Row widget(水平方向布局组件)

属性:

children <Widget>[ ]:相当于这是一个组件数组,【】里面可以全放组件。

 children: <Widget>[
            new Expanded(  //expanded是灵活性的,可以根据具体信息平均分配,合适Android页面大小,可灵活运用expand来调整按钮的大小。
              child: RaisedButton(
              onPressed: (){},
              color:Colors.red ,
              child: Text('red Button'),
            ),
            ),
            Expanded(
             child:RaisedButton(
              onPressed: (){},//点击按钮时触发的事件,或者要执行的任务。
              color:Colors.lightBlue ,
              child: Text('blue Button'),
            ),
            ),
            Expanded(
            child: RaisedButton(
              onPressed: (){},
              color:Colors.lightGreen ,
              child: Text('Green button'),
            ),
            ),
          ],

 

crossAxisAlignment:水平方向的对齐方式(start(开始对齐(左)),end(末尾对齐(右)), center(居中,默认))

 

 crossAxisAlignment:CrossAxisAlignment.start,

 

 

 

Expanded widget是灵活组件,根据具体信息平均分配空间布局大小

组件实例如上

实例代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'Row widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Row widget'),
        ),
        body: Row(   //水平组件布局
         crossAxisAlignment:CrossAxisAlignment.start,
          children: <Widget>[
            new Expanded(  //expanded是灵活性的,可以根据具体信息平均分配,合适Android页面大小,可灵活运用expand来调整按钮的大小。
              child: RaisedButton(
              onPressed: (){},
              color:Colors.red ,
              child: Text('red Button'),
            ),
            ),
            Expanded(
             child:RaisedButton(
              onPressed: (){},//点击按钮时触发的事件,或者要执行的任务。
              color:Colors.lightBlue ,
              child: Text('blue Button'),
            ),
            ),
            Expanded(
            child: RaisedButton(
              onPressed: (){},
              color:Colors.lightGreen ,
              child: Text('Green button'),
            ),
            ),
          ],
        ),
      ),
    );
  }
}

 

10、Column Widget(垂直方向布局组件)

属性:
crossAxisAlignment:CrossAxisAlignment.center ,//对齐方式布局center为默认布局,他是相对与字体的长度对齐(水平方向副轴)

mainAxisAlignment: MainAxisAlignment.center,//垂直方向为主轴
同上,有children<Widget>[]
注意:区分主轴和副轴的,如果是水平方向主轴就是横向的,如果是垂直方向的布局,主轴就是纵轴。
实例代码:
//垂直方向上的组件
import 'package:flutter/material.dart';

void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'Column widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Column widget'),
        ),
        body: Center(  //在中间显示居中
          child:Column(   //水平组件布局
         crossAxisAlignment:CrossAxisAlignment.center ,//对齐方式布局center为默认布局,他是相对与字体的长度对齐(水平方向副轴)
          mainAxisAlignment: MainAxisAlignment.center,//垂直方向为主轴
        children: <Widget>[
          Expanded(  //灵活组件布局Expanded平均分配页面的比例,假如没加Expanded时不灵活布局
            child:Text('Welcome to flutter'),
          ),
          Text('my name is haha'),//不灵活布局
          Expanded(
            child:Text('i love web'),//灵活布局
          ),
          Text('i like flutter'),//不灵活布局
          Text('Welcome study Column'),//不灵活布局
        ],
        ),
      ),
      ),
    );
  }
}
View Code

11、Card widget(卡片组件)

卡片:就是设置个人卡片或者

举例卡片和Column(垂直方向布局),列表瓦片(ListTile)混合用

代码示例:

//卡片布局

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var card = new Card(  //卡片布局
      child: new Column(
        children: <Widget>[
          new ListTile(   //列表瓦片
            title: Text('姓名:李大妹',style: TextStyle(color:Colors.yellow,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=745669936,3962756491&fm=26&gp=0.jpg'),
            trailing: Icon(Icons.account_box),
          ),

          new Divider(  //分割线
            height: 20.0,
            color: Colors.pink,),//

          new ListTile(
            title: Text('姓名:李二妹',style: TextStyle(color:Colors.red,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3017568428,4147600612&fm=26&gp=0.jpg'),
            trailing: Icon(Icons.account_box),
          ),

          new Divider( height: 20.0,
            color: Colors.pink,),

          new ListTile(
            title: Text('姓名:李三妹',style: TextStyle(color:Colors.lightBlue,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575026182108&di=e69c3887d571ba4e5166fbe03893976c&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201708%2F02%2F20170802084658_UViBH.jpeg'),
            trailing: Icon(Icons.account_box),
          ),

          new Divider( height: 20.0,
            color: Colors.pink,),

          new ListTile(
            title: Text('姓名:李老大',style: TextStyle(color:Colors.black,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1838136197,2974424351&fm=26&gp=0.jpg'),
            trailing: Icon(Icons.account_box),
          ),

          new Divider(
            height: 20.0,
            color: Colors.pink,
          ),

          new ListTile(
            title: Text('姓名:李老幺',style: TextStyle(color:Colors.lightGreenAccent,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3722902562,2037055323&fm=26&gp=0.jpg'),
            trailing: Icon(Icons.account_box),
          ),
        ],
      ),
    );


    return MaterialApp(
      title: 'Card Widget',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Card study'),
        ),
        body: Center(
          child: card,
        ),
      ),
    );
  }
}
View Code

12、Dviider Widget(分割线组件)

用于分割组件与组件

常用属性:

height:高度

color:颜色

具体代码:

 new ListTile(
            title: Text('姓名:李三妹',style: TextStyle(color:Colors.lightBlue,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575026182108&di=e69c3887d571ba4e5166fbe03893976c&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201708%2F02%2F20170802084658_UViBH.jpeg'),
            trailing: Icon(Icons.account_box),
          ),

          new Divider( height: 20.0,
            color: Colors.pink,),

          new ListTile(
            title: Text('姓名:李老大',style: TextStyle(color:Colors.black,fontWeight: FontWeight.bold,),),
            subtitle: Text('电话:123466789',style: TextStyle(fontWeight: FontWeight.bold),),
            leading: Image.network('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1838136197,2974424351&fm=26&gp=0.jpg'),
            trailing: Icon(Icons.account_box),
          ),

13、RaisedButton Widget(凸起按钮组件)

一般所有的组件都有(触发事件属性)

属性:

onpressed(出发事件)

onPressed: (){
          //Navigator是对象属性,就是我们要跳转的页面
          Navigator.push(context, MaterialPageRoute(  //MaterialPageRoute路由组件,搜索,push是跳转到下一页
              builder:(context)=>new Secend(),//第二页面自定义类Secend,  builder建一个函数
          ),
          );//Navigator
        },

onpressed:(){};大括号里有常用属性,Navigator是一个导航器,有两个导航方式:Navigator.push(context,Route),Navigator.pop(context)

Navigator.push(context,Route)第一个参数是上下文,第二个参数是路由导航属性(MaterialPageRoute),它里面又包含了一个builder属性,builder是一个匿名函数生成器。

一般导航页面时利用按钮中的触发事件onPressed来实现的,

代码示例:

 

//导航页面跳转
import 'package:flutter/material.dart';
void main(){
  runApp(MaterialApp(
    title: 'dao hang ye mian',
    home:First(),//第一页自定义类First
  ));
}
class First extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('首页'),
      ),
      body: RaisedButton(  //凸起按钮
        child: Text('下一页'),
        onPressed: (){
          //Navigator是对象属性,就是我们要跳转的页面
          Navigator.push(context, MaterialPageRoute(  //MaterialPageRoute路由组件,搜索,push是跳转到下一页
              builder:(context)=>new Secend(),//第二页面自定义类Secend,  builder建一个函数
          ),
          );//Navigator
        },
      ),
    );
  }
}

class Secend extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: '第二页',
      home: Scaffold(
       appBar: AppBar(
         title: Text('第二页'),
       ),
        body: RaisedButton(
          child: Text('返回上一页'),
          onPressed: (){
            Navigator.pop(context);//pop是跳转到上一页
          },
        ),
      ),
    );
  }
}

 

动态传参导航页面代码示例,

假如看不懂就看视频解析:技术胖的flutter基础教程,

https://search.bilibili.com/all?keyword=flutter&from_source=banner_search

或者搜索

http://www.jspang

代码示例

import 'package:flutter/material.dart';

//自定义对象
  class ProDuct{
    //数据类型的声明
  final String title;//商品列表,  参数
  final String productinfo;//商品信息,  参数
  ProDuct(this.title,this.productinfo);//构造函数,传参
  }


  //类入口
void main(){
    runApp(MaterialApp(
      title: 'daohanlist',
      home: ProDuctList(  //自定义入口名
        //generate是传参生成器,
        produrcts:List.generate(10,(i)=>ProDuct('商品属性 $i','这是一个商品属性,编号为:$i'))//给类传参,produrcts自定义属性变量
      ),
    ),
    );
}


class ProDuctList extends StatelessWidget{
final List<ProDuct> produrcts;//变量
ProDuctList({Key key,@required this.produrcts}):super(key:key);//声明传参
@override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('商品列表'),
      ),
      body: ListView.builder(  //动态传参一般用ListView.builder
        itemCount: produrcts.length,//第一个参数
        itemBuilder: (context,index){   //匿名函数的参数,(上下文context,索引index)
          return ListTile(
            title: Text(produrcts[index].title),//显示各一个参数
            onTap: (){
              Navigator.push(context,MaterialPageRoute(
                builder: (context)=>new Productinfo(produrct:produrcts[index]),//相当于produrct就是produrcts[index],两个是相同的值相同对象
              ));
            },//点击右响应事件
          );
        }
      ),
    );
  }
}
class Productinfo extends StatelessWidget{
    final ProDuct produrct;//定义一个ProDuct类中的示例对象produrct
    Productinfo({Key key,@required this.produrct}):super(key:key);//super关键字是代表继承父类
    @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('${produrct.title}'),//传ProDuct中的参数
      ),
      body: Container(
        height: 500.0,
        color: Colors.pink,
        child:Center(child:Text('${produrct.productinfo}'),),),//传ProDuct中的商品信息,变量名已在上诉声明
    );
  }
}

带有返回数据的导航页面

Dart中的异步请求和等待和ES6中的方法很像,直接使用async...await就可以实现。比如下面作了一个的方法,

然后进行跳转,注意这时候是异步的。等待结果回来之后,我们再显示出来内容。具体代码如下:

代码:

 _NavigateToxiaojiejie(BuildContext context) async{  //async 表示异步, _NavigateToxiaojiejie自定义内部函数(下划线开头),也是要接受上下文
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context)=> SecendPage(),
      ),
    );
    Scaffold.of(context).showSnackBar(  //展示返回的数据
        SnackBar(    //重要
          content: Text('$result'),
        ),
    );//snackBar是scaffold中的属性,(showSnackBar)就是接受子页面返回的信息
  }
}

SnackBar的使用

SnackBar是用户操作后,显示提示信息的一个控件,类似Tost,会自动隐藏。

SnackBar是以ScaffoldshowSnackBar方法来进行显示的。

Scaffold.of(context).showSnackBar(  //展示返回的数据
        SnackBar(    //重要
          content: Text('$result'),
        ),
    );//snackBar是scaffold中的属性,(showSnackBar)就是接受子页面返回的信息

返回数据的方式

返回数据其实是特别容易的,只要在返回时带第二个参数就可以了。context之后的就是第二个参数。

  Navigator.pop(context,'腰围3cm,电话号码:123453');

代码示例:

import 'package:flutter/material.dart';
import 'package:flutter_app/%E5%AF%BC%E8%88%AA%E9%A1%B5%E9%9D%A21.dart';

void main(){
  runApp(MaterialApp(
    title: 'yi bu daohang',
    home: FistPage(),
  ));
}

class FistPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text('找人'),),
      body: Center(
        child: NextButton(),
      ),
    );
  }
}

class NextButton extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return RaisedButton(
      onPressed: (){_NavigateToxiaojiejie(context);},// _NavigateToxiaojiejie自定义的函数,context相当于类中的默认self
      child: Text('小姐姐信息',style: TextStyle(
        color: Colors.red,fontWeight: FontWeight.bold,fontSize: 20.0,
      ),),
    );
  }
  _NavigateToxiaojiejie(BuildContext context) async{  //async 表示异步, _NavigateToxiaojiejie自定义内部函数(下划线开头),也是要接受上下文
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context)=> SecendPage(),
      ),
    );
    Scaffold.of(context).showSnackBar(  //展示返回的数据
        SnackBar(    //重要
          content: Text('$result'),
        ),
    );//snackBar是scaffold中的属性,(showSnackBar)就是接受子页面返回的信息
  }
}

class SecendPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('小姐姐信息'),
      ),
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('长腿小姐姐'),
            onPressed: (){
              Navigator.pop(context,'大腿长2米,电话号码:46466577');
            },
          ),
          RaisedButton(
            child: Text('小蛮腰小姐姐'),
            onPressed: (){
              Navigator.pop(context,'腰围3cm,电话号码:123453');
            },
          ),
        ],
      ),
    );
  }
}
带有返回数据的导航页面

 

四、静态资源和项目图片的处理

pubspec.yaml 文件

如果想配置项目资源文件,就需要使用pubspec.yaml文件,需要把资源文件在这里声明。

比如在项目根目录下新建了一个image文件夹,文件夹下面放了一个图片,图片的名称叫做00.jpg

那我们在pubspec.yaml文件里就要写如下代码进行声明。

assets:
    - image/00.jpg

使用项目图片资源

有了声明后,我们就可以直接在项目中引用这个文件了。这里使用最简单的代码结构,只用了一张图片。代码如下:

import 'package:flutter/material.dart';
void main(){
  runApp(MyApp());
}
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'hello world',
      home: Scaffold(
        appBar: AppBar(
          title: Text('image'),
        ),
        body: Image.asset('image/00.jpg'),//这里就是从项目包里打开文件
      ),

    );
  }
}

Flutter客户端打包

到现在为止,我相信小伙伴都能做出一些漂亮的页面了,也有了难道朋友面前显一显的冲动。想要安装到手机上,我们必须要进行打包,这节课我们就学学Android客户端如何打包apk。

看视屏

http://www.jspang.com/posts/2019/02/01/flutter-base4.html

配置APP的图标

想配置APP的图片,你需要找到下面的目录:

项目根目录/android/app/src/main/res/

进入之后你会看到很多mipmap-为前缀命名的文件夹,后边的是像素密度,可以看出图标的分辨率。

  • mdpi (中) ~160dpi
  • hdpi (高) ~240dip
  • xhdpi (超高) ~320dip
  • xxhdpi (超超高) ~480dip
  • xxxhdpi (超超超高) ~640dip

将对应像素密度的图片放入对应的文件夹中,图片记得用png格式,记得名字要统一,才能一次性进行配置。

#AndroidManifest.xml 文件

这个文件主要用来配置APP的名称、图标和系统权限,所在的目录在:

项目根目录/android/app/src/main/AndroidManifest.xml

 

生成 keystore

这里的坑挺多的,小伙伴一定要注意。官方写的非常简单,只要在终端运行如下代码就可以成功,但事实是报错。

下代码官方写:

keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alia

出现这种错误,见链接
http://jspang.com/static/upload/20181217/5xuQKZ9PfP4YniYgWcNR53j4.png


根本找不到这个目录,真的很坑,其实我们只是没有配置环境变量。但是为了一个包配置环境变量是不知道的。

这时候可以用下面的命令找到keytool.exe的位置。

在你的终端运行如下代码:

flutter doctor -v
我的是在webstorm软件终端下,假如是在vs code软件下就在vs code终端运行,
http://jspang.com/static/upload/20181217/cHrgJ3SdAqFk1Ivta82vIP7g.png

这时候你直接拷贝命令并进行输入,但这里也有个坑,就是如果文件夹中间带有空空,你需要用带引号扩上。
D:\Program\Android\'Android Studio'\jre\bin\keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key


这就可以了吗?那你就太天真了,还是会报错。
http://jspang.com/static/upload/20181217/7dTEF6Pshi4qew0-p-MWXNtX.png
这个错误的主要问题是目录不存在和没有写权限,所以我们要更换一个有写权限的目录。我们把命令改成了下面的形式。

 D:\Program\Android\'Android Studio'\jre\bin\keytool -genkey -v -keystore D:\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

这时候就可以创建成功了。你的D盘下面就会有一个Jks的文件,记住这个文件不能共享给任何人。

有了这个key.jks文件后,可以到项目目录下的android文件夹下,创建一个名为key.properties的文件,并打开粘贴下面的代码。

storePassword=<password from previous step>    //输入上一步创建KEY时输入的 密钥库 密码
keyPassword=<password from previous step>    //输入上一步创建KEY时输入的 密钥 密码
keyAlias=key
storeFile=<E:/key.jks>    //key.jks的存放路径

我的文件最后是这样的:

storePassword=123123
keyPassword=123123
keyAlias=key
storeFile=D:/key.jks

这个工作中也不要分享出去哦,这个Key就算生成成功了。

#配置key注册

key生成好后,需要在build.gradle文件中进行配置。这个过程其实很简单,就是粘贴复制一些东西,你是不需要知道这些文件的具体用处的。

第一项:

进入项目目录的/android/app/build.gradle文件,在android{这一行前面,加入如下代码:

def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

把如下代码进行替换

buildTypes {
    release {
        signingConfig signingConfigs.debug
    }
}

替换成的代码:

signingConfigs {
    release {
        keyAlias keystoreProperties['keyAlias']
        keyPassword keystoreProperties['keyPassword']
        storeFile file(keystoreProperties['storeFile'])
        storePassword keystoreProperties['storePassword']
    }
}
buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}

#生成apk

直接在终端中输入:

flutter build apk

这时候就打包成功了,剩下的安装过程我就省略,不作过多的介绍了。

安装过程见视频:

https://www.bilibili.com/video/av35800108?p=25