Flutter框架概览

Flutter框架概览

Flutter是什么

  • 是一款移动应用程序SDK,一份代码可以同时生成ios和Android两个高性能、高保真的应用程序
  • 目标是使开发人员能够交付在不同平台上都感觉自然流畅的高性能应用程序。我们兼容滚动行为,排版,图标等方面的差异

Flutter优势

  • 跨平台:至少可以跨4种平台,甚至支持嵌入式开发,常用的有(Linux,Android,IOS,甚至可以在谷歌最新的操作系统上Fuchsia进行运行),经过第三方扩展,甚至可以跑在MacOS和Windows上。Flutter算是支持平台最多的框架,良好的跨平台性,减少开发成本
  • 原生用户界面:它是原生的,体验好,性能好
  • 开源免费

主流框架的对比

  • Cordova:Cordova基于网页技术进行包装,利用插件的形式开发移动应用
  • RN(React Native):RN的效率由于是将View编译成了原生View,所以效率上要比基于Cordova的HTML5高很多,但是它也有效率问题,RN的渲染机制是基于前端框架的考虑,复杂的UI渲染是需要依赖多个view叠加,RN的列表方案不友好
  • Flutter:在渲染技术上,选择了自己实现(GDI),有更好的可控性,使用了新的语言Dart,避免了RN的那种通过桥接器与Javascript通讯导致效率底下的问题,所以性能方面比RN更高一筹;

120fps超高性能

Flutter采用GPU渲染技术,所以性能极高

Flutter编写的应用是可以达到120fps(每秒传输帧数),完全可以胜任游戏的制作,RN的性能只能达到60fps。

核心原则

Flutter包括一个现代的响应式框架,一个2D渲染引擎,现成的widget和开发工具

Dart语法Function函数

Dart是面向对象的语言,即使是函数也是对象,并且属于Function类型的对象,这意味着函数可以分配给变量或作为参数传递给其他函数

Dart是一切皆对象,包括数字和函数

StatefulWidget和StatelessWidget

  • StatefulWidget:具有可变状态的窗口部件,也就是你在使用应用的时候就可以随时变化,如果常见的进度条,随着进度不断变化
  • StatelessWidge:不可变状态窗口部件,也就是你在使用时不可以改变,如果固定的文字

flutter的基本代码

import 'package:flutter/material.dart';
//主函数(入口函数),下面我会简单说说Dart的函数
void main() =>runApp(MyApp());
// 声明MyApp类
class MyApp extends StatelessWidget{
  //重写build方法
  @override
  Widget build(BuildContext context){
    //返回一个Material风格的组件
   return MaterialApp(
      title:'Welcome to Flutteraa',
      home:Scaffold(
        //创建一个Bar,并添加文本
        appBar:AppBar(
          title:Text('Welcome to Flutter'),
        ),
        //在主体的中间区域,添加一个hello world 的文本
        body:Center(
          child:Text(
            'Hello JSPang  ,非常喜欢前端,并且愿意为此奋斗一生。我希望可以出1000集免费教程。',
  textAlign:TextAlign.left,
  overflow:TextOverflow.ellipsis,
  maxLines: 1,
  style: TextStyle(
    fontSize:25.0,
    color:Color.fromARGB(255, 255, 150, 150),
    decoration:TextDecoration.underline,
    decorationStyle:TextDecorationStyle.solid,
  ),
          ),
        ),
      ),
    );
  }
}

常用组件

Container容器组件的使用

Alignment属性:这个属性针对的是Container内child的对齐方式,也就是容器子内容的对齐方式,并不是容器本身的对齐方式

child:Container(
             child:new Text('Hello JSPang',style: TextStyle(fontSize: 40.0),),
             alignment: Alignment.center,
           ),
  • bottomCenter:下部居中对齐
  • bottomLeft:下部左对齐
  • bottomRight:下部右对齐
  • center:纵横双向居中对齐
  • centerLeft:纵向居中横向居左对齐
  • centerRight:纵向居中横向居右对齐
  • topLeft:顶部左侧对齐
  • topCenter:顶部居中对齐
  • topRight:顶部居左对齐

设置宽,高和颜色属性

设置宽,高和颜色属性只要在属性名称后加入浮点型数字就可以

child:Container(
  child:new Text('Hello JSPang',style: TextStyle(fontSize: 40.0),),
  alignment: Alignment.center,
  width:500.0,
  height:400.0,
  color: Colors.lightBlue,
),

padding,margin,decoration


padding

padding:const EdgeInsets.all(10.0),
padding:const EdgeInsets.fromLTRB(value1,value2,value3,value4)
// 我们用EdgeInsets.fromLTRB(value1,value2,value3,value4) 可以满足我们的需求,LTRB分别代表左、上、右、下。

margin

// margin是container和外部元素的距离
 margin: const EdgeInsets.all(10.0),
 margin:const EdgeInsets.fromLTRB(value1,value2,value3,value4)

decoration

// decoration是container的修饰器,主要的功能是设置背景和边框
// 如果要给背景加入一个渐变,需要使用BoxDecoration这个类,(注意,如果设置了decoration,就不要再设置color属性了,会冲突)
decoration: BoxDecoration(
        gradient: const LinearGradient(colors: [Colors.lightBlue,Colors.greenAccent,Colors.purple] )),


border

border:Border.all(width:2.0,color:Colors.red)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 学习',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Iris'),
        ),
        body: Center(
          child: Container(
            child: new Text('世界那么大,我想去看看',style: TextStyle(fontSize: 20.0),),
            alignment: Alignment.center,
            width: 500.0,
            height: 400.0,
            padding: const EdgeInsets.fromLTRB(10.0, 30.0, 0.0, 0.0),
            margin: const EdgeInsets.all(10.0),
            decoration: BoxDecoration(
              gradient: const LinearGradient(
                colors: [Colors.lightBlue,Colors.greenAccent,Colors.purple]
              ),
              border: Border.all(width: 1.0,color: Colors.red)
            ),
          ),
        ),
      ),
    );
  }
}

加入图片的几种方式

  • Image.asset:加载资源图片,就是加载项目资源目录中的图片,加入图片后会增大打包的包体体积,用的是相对路径
  • Image.network:网络资源图片,意思就是需要加入一段http://xxxx.xxx的这样的网络路径地址
  • Image.file:加载本地图片,就是加载本地文件中的图片,这是一个绝对路径,跟包体无关
  • Image.memory:加载Uint8List资源图片

fit属性的设置

  • BoxFit.fill:全图显示,图片会被拉伸,并充满父容器
  • BoxFit.contain:全图显示,显示原比例,可能会有空隙
  • BoxFix.cover:显示可能拉伸,可能裁切,充满(图片要充满整个容器,还不变形 )
  • BoxFit.fitWidth:宽度充满(横向充满),显示可能拉伸,可能裁切
  • BoxFit.fitHeight:高度充满(竖向充满),显示可能拉伸,可能裁切
  • BoxFit.scaleDown:效果和contain差不多,但是此属性不允许显示超过源图片大小,可小不可大

图片的混合模式

图片混合模式(colorBlendMode)和color属性配合使用,能让图片改变颜色,里面的模式非常多,产生的效果也非常丰富

child:new Image.network(
  'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2247692397,1189743173&fm=5',
    color: Colors.greenAccent,
    colorBlendMode: BlendMode.darken,
),
  • color:是要混合的颜色,如果你只设置color是没有意义的
  • colorBlendMode:是混合模式

repeat图片重复

  • ImageRepeat.repeat :横向和纵向都进行重复,直到铺满整个画布
  • ImageRepeat.repeatX:横向重复,纵向不重复
  • ImageRepeat.repeatY:纵向重复,横向不重复
child:new Image.network(
  'http://jspang.com/static/myimg/blogtouxiang.jpg',
   repeat: ImageRepeat.repeat,
),
body: Center(
          child: Container(
             child:new Image.network(
                  'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2247692397,1189743173&fm=5',
                  scale: 1.0,
                  // fit: BoxFit.cover,
                  color: Colors.greenAccent,
                  colorBlendMode: BlendMode.darken,
                  repeat: ImageRepeat.repeat,
              ),
              width: 500.0,
              height: 600.0,
              color: Colors.lightBlue,
          ),
        ),

ListView列表组件简介

ListTile组件

body: new ListView(
  children:<Widget>[
    new ListTile(
      leading:new Icon(Icons.access_time),
      title:new Text('access_time')
    ),
    new ListTile(
      leading:new Icon(Icons.account_balance),
      title:new Text('account_balance')
    ),
  ]
),

图片列表的使用

body: new ListView(
  children: <Widget>[
      new Image.network(     'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2247692397,1189743173&fm=5'),
      new Image.network(        'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1569462993,172008204&fm=5'),
      new Image.network(     'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1853832225,307688784&fm=5')
          ],
        ),

横向列表的使用

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,
                )
              ],
            ),
          ),
        )

scrollDirection属性

ListView组件的scrollDirection属性只是两个值,一个是横向滚动,一个是纵向滚动,默认的就是垂直滚动,所以如果是垂直滚动,一般不进行设置

  • Axis.horizontal:横向滚动或者叫水平方向滚动
  • Axis.vertical:纵向滚动或者叫垂直方向滚动

代码优化

// 使用类,减少嵌套
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(
          body:Center(
          child:Container(
            height:200.0,
            child:MyList()
            ),
          ),
        ),
      );
  }
}
class MyList extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return 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,
          ),
        ],
    );
  }
}

List类型的使用

List是Dart的集合类型之一,可以理解为数组,它声明的几种方式

  • var myList = List():非固定长度的声明
  • var myList = List(2):固定长度的声明
  • var myList = List<string>():固定类型的声明方式
  • var myList = [1,2,3]:对List直接赋值

使用一个List传递,然后直接用List中的generate方法进行生产List里的元素。最后生产一个带值的List变量

void main () => runApp(MyApp(
  items: new List<String>.generate(1000, (i)=> "Item $i")
));
// main函数的runApp中调用了MyApp类,再使用类传递了一个item参数,并使用generate生成器对item进行赋值
// generate方法传递两个参数,第一个参数是生成的个数,第二个是方法

接受参数

final List<String> items;
MyApp({Key key, @required this.items}):super(key:key)
// 构造函数,@required是比传的意思,:super如果父类没有无名无参的默认构造函数,子类必须手动调用一个父类构造函数

动态列表ListView.builder()

import 'package:flutter/material.dart';
void main () => runApp(MyApp(
   // 传递参数
  items: new List<String>.generate(1000, (i)=> "Item $i")
));
class MyApp extends StatelessWidget{
   // 接受参数
  final List<String> items;
  MyApp({Key key, @required this.items}):super(key:key);
  @override
  Widget build(BuildContext context ){
      return MaterialApp(
        title:'ListView widget',
        home:Scaffold(
          // 动态列表
          body:new ListView.builder(
            itemCount:items.length,
            itemBuilder:(context,index){
              return new ListTile(
                title:new Text('${items[index]}'),
              );
            }
          )
        ),
      );
  }
}

GridView网格列表组件

网格列表常用来显示多张图片,类似于相册功能

   body: new GridView.count(
          padding: const EdgeInsets.all(20.0),
          crossAxisSpacing: 10.0,
          crossAxisCount: 3,
          children: <Widget>[
            const Text('我的呱呱'),
            const Text('我喜欢吃'),
            const Text('我是个淑女的小姐姐'),
            const Text('我是个会写代码的萌妹纸'),
            const Text('我喜欢吃火锅'),
            const Text('我喜欢看书')
          ],
        )
       // padding 内边距
       // crossAxisSpacing: 网格间的空挡,相当于每个网格间的距离
       // crossAxisCount: 网格的列数,相当于一行放置网格的数量
import 'package:flutter/material.dart';
// 主函数(入口函数)
void main() => runApp(MyApp(
  // 传递参数
  // items: new List<String>.generate(10, (i)=>"Item $i")
));

// 声明MyApp类
class MyApp extends StatelessWidget{
  // 接受参数
  // final List<String> items;
  // MyApp({Key key, @required this.items}):super(key:key);
// 重写build方法
  @override
  Widget build(BuildContext context){
    // 返回一个Material风格的组件
    return MaterialApp(
      title: '好好学习',
      home: Scaffold(
        // 主体中间区域
        body: new GridView(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            mainAxisSpacing: 2.0,
            crossAxisSpacing: 2.0,
            childAspectRatio: 0.7
          ),
          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),
          ],
        )
      ),
    );
  }
}
// childAspectRatio:宽高比

布局

第01节水平布局Row的使用

Flutter中的row控件是水平控件,可以让Row子元素进行水平排列

Row控件可以分为灵活排列非灵活排列两种

不灵活水平布局:根据Row子元素的大小,进行布局,如果子元素不足,会留有空间,如果子元素超出,会警告

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

灵活布局:使用Expanded来解决空隙问题,在按钮外边加入Expanded就可以了

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

注意:还可以灵活和不灵活混合使用

第02节:垂直布局Column组件

Column组件就是垂直布局控件,能够将子组件垂直排列

body:Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
            Text('I am JSPang'),
            Text('my website is jspang.com'),
            Text('I love coding')
        ],
    )
// CrossAxisAlignment.star:居左对齐。
// CrossAxisAlignment.end:居右对齐。
// CrossAxisAlignment.center:居中对齐。

主轴和副轴

mainAxisAlignment 主轴对齐方式

  • main轴:主轴(根据组件判断主轴,column组件,和Row组件)
  • cross轴:副轴

第03节:Stack层叠布局

// 声明MyApp类
class MyApp extends StatelessWidget{
  // 接受参数
  // final List<String> items;
  // MyApp({Key key, @required this.items}):super(key:key);
// 重写build方法
  @override
  Widget build(BuildContext context){
    // 返回一个Material风格的组件
    var stack = new Stack(
      alignment: const FractionalOffset(0.5, 0.95),
      children: <Widget>[
        new CircleAvatar(
          backgroundImage: new NetworkImage('https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2247692397,1189743173&fm=5'),
          radius: 100.0,
        ),
        new Container(
          decoration: new BoxDecoration(
            color: Colors.lightGreen
          ),
          padding: EdgeInsets.fromLTRB(20.0,3.0,20.0,3.0),
          child: Text('布偶',style: TextStyle(fontSize: 18.0,color: Colors.blueGrey),),
        )
      ],
    );
    return MaterialApp(
      title: '好好学习',
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('水平方向布局'),
        ),
        // 主体中间区域
        body: Center(
          child:stack
        )
      ),
    );
  }
}

重叠布局的alignment属性

alignment属性是控制层叠的位置的,建议在两个内容进行层叠时使用,它有两个值X轴距离和Y轴距离,值是从0到1的,都是从上层容器的左上角开始计算的

alignment: const FractionalOffset(0.5, 0.8),

CircleAvatar组件的使用

CircleAvatar这个常用来作头像,组件里面有个radius的值可以设置图片的弧度

new CircleAvatar(
          backgroundImage: new NetworkImage('https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2247692397,1189743173&fm=5'),
          radius: 100.0,
        ),

Stack的Position属性

层叠定位组件

Positioned组件的属性

  • bottom:距离层叠组件下边的距离
  • left:距离层叠组件左边的距离
  • right:距离层叠组件右边的距离
  • top:距离层叠组件上边的距离
  • width:距离层叠组件定位组件的宽度
  • height:距离层叠组件定位组件的高度
 new Positioned(
     bottom:10.0,
     right:10.0,
     child: new Text('技术胖'),
 )

第05节:卡片组件布局

类似与ViewList,但是列表会以物理卡片的形态进行展示

卡片式布局默认撑满整个外部容器,如果想要设置卡片的高度,需要在外部容器就进行制定

var card = new Card(
     child: Column(
       children: <Widget>[
        ListTile(
           title: Text('湖南省益阳市',style:TextStyle(fontWeight: FontWeight.w500)),
           subtitle: Text('伊:13710145724'),
           leading: new Icon(Icons.account_box,color:Colors.lightBlue),
          ),
        new Divider(),
        ListTile(
          title: Text('湖南省长沙市',style:TextStyle(fontWeight: FontWeight.w500)),
          subtitle: Text('伊:13710145724'),
          leading: new Icon(Icons.account_box,color:Colors.lightBlue),
        ),
        new Divider(),
        ListTile(
          title: Text('湖南省常德市',style:TextStyle(fontWeight: FontWeight.w500)),
          subtitle: Text('伊:13710145724'),
          leading: new Icon(Icons.account_box,color:Colors.lightBlue),
        ),
        new Divider(),
       ],
     ),
   );
//new Divider()分割线

页面导航和其他

第01节:一般页面导航和返回

RaiseButton按钮组件

基本属性:

  • child:可以放入容器,图标,文字
  • onPressed:点击事件的响应,一般会调用Navigator组件

Navigator.push和Navigator.pop

  • Navigator.push:是跳转到下一个页面,他要接受两个参数一个是上下文context,另一个是要跳转的函数
  • Navigator.pop:是返回到上一个页面,使用时传递一个context参数,注意,必须是有上级页面的,也就是说上级页面使用了Navigator.push
import 'package:flutter/material.dart';
void main(){
  runApp(MaterialApp(
    title:'导航演示1',
    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:Text('返回'),
          onPressed: (){
            Navigator.pop(context);
          },
      ))
    );
  }
}

第02节:导航参数的传递和接受

Awesome Flutter snippets插件的使用:帮助快速生成常用的Flutter代码片段


声明数据结构类

Dart中可以使用类来抽象一个数据,比如我们模仿一个商品信息,有商品标题和商品描述。定义一个product类,里面有两个字符变量,title和description

  • title:商品标题
  • description:商品详情描述
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组件,然后使用路由MaterialPageRouter传递参数

Navigator.push(
    context,
    MaterialPageRouter(
    builder:(context)=>new       ProductDetail(product:products[index])
    )
)

第04节:页面跳转并返回数据

异步请求和等待

Dart的异步请求和等待和ES6的方法很像,直接使用async....await就可以实现

// async 是启用异步方法
_navigateToXiaoJieJie(BuildContext context) async{
    final result = await Navigator.push(
        context,
        MaterialPageRouter(
            builder:(context)=>Xiaojiejie()
        )
    );
    Scaffold.of(context).showSnackBar(SnackBar(content:Text('$result')));
}

SnackBar的使用

SnackBar是用户操作后,显示提示信息的一个控件,类似Tost,会自动隐藏。SnackBar是以ScaffoldshowSnackBar方法来进行显示的

Scaffold.of(context).showSnackBar(SnackBar(content:Text('$result')))

返回数据的方式

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

Navigator.pop(context,'xxx');//xxx就是返回的参数

Demo

import 'package:flutter/material.dart';
void main(){
  runApp(MaterialApp(
    title: '页面跳转放回数据',
    home: FirstPage(),  
  ));
}

class FirstPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('找伊大美女要电话号码'),
      ),
      body: Center(
        child: RouterButton(),
      ),
    );
  }
}


class RouterButton extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return RaisedButton(
      child: Text('伊伊是大美女'),
      onPressed: (){
        _navigateToXiaoJieJie(context);
      },
    );
  }

  _navigateToXiaoJieJie(BuildContext context) async{ //async是启用异步方法
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context)=>XiaoJieJie())
    );
    Scaffold.of(context).showSnackBar(SnackBar(content: Text('$result')));
  }
}

class XiaoJieJie extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('我是小姐姐'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            RaisedButton(
              child: Text('大长腿小姐姐'),
              onPressed: (){
                Navigator.pop(context,'大长腿姐姐:13710145724');
              },
            ),
            RaisedButton(
              onPressed: (){
                Navigator.pop(context,'小蛮腰姐姐:13710145724');
              },
              child: Text('小蛮腰小姐姐'),
            )
          ],
        ),
      ),
    );
  }
}

第05节:静态资源和项目图片的处理

注意:pubspec.yaml文件,配置项目资源文件,在里面声明资源文件

  assets:
    - images/blogtouxiang.jpg

使用项目图片资源

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Image.asset('images/blogtouxiang.jpg'),
    );
  }
}

第06节:Flutter客户端打包

配置APP的图标

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

AndroidManifest.xml文件

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

项目根目录/android/app/src/main/AndroidManifest.xml
android:label="flutter_app"   //配置APP的名称,支持中文
android:icon="@mipmap/ic_launcher" //APP图标的文件名称

生成keystore

打包详情

https://jspang.com/post/flutter4.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 特别说明 当前博客平台账号已废弃,如果有使用细节问题请前往我新博客平台进行讨论交流。 个人博客平台 HuRuWo的...
    善笃有余劫阅读 4,935评论 0 30
  • 国庆后面两天在家学习整理了一波flutter,基本把能撸过能看到的代码都过了一遍,此文篇幅较长,建议保存(star...
    Nealyang阅读 4,337评论 1 17
  • 已经很长的时间, 似乎是忘了年月。 她声音里透露出些许不安, 我知道一定是风霜侵袭了她, 那曾乌黑亮丽的头发。 隐...
    只是从未孤独阅读 121评论 2 0
  • 一大早我们坐106又坐39路,虽然下着雨,但也不能阻挡我们要去看年糕的心情,我们等公交车等了很久,终于有一辆39路...
    轻舞飞扬nice阅读 143评论 0 1
  • 今天给大家推荐的这部励志电影,《麦克法兰》是由妮基·卡罗执导,凯文·科斯特纳、摩根·塞勒、玛丽亚·贝罗等主演的运动...
    monasp阅读 335评论 0 0