flutter学习总结(语法,组件,布局,和路由)

mac2024-05-13  34

一.helloworld应用

按国际惯例,写来一个hello world应用跑一遍.

创建项目

启动 VS Code 调用 View>Command Palette… 输入 ‘flutter’, 然后选择 ‘Flutter: New Project’ action 输入 Project 名称 (如myapp), 然后按回车键 指定放置项目的位置,然后按蓝色的确定按钮 等待项目创建继续,并显示main.dart文件 开始代码,写在根目录\lib\main.dart文件中,这就是Flutter主文件.

基本思路:

引入flutter包 入口函数 声明MyApp类 重写build方法,它返回一个MaterialApp风格的组件 在Material组件的home属性里赋值一个Scaffold组件 在Scaffold组件里创建appBar和body 在body的中间区域添加hello world文本

填充代码:

// flutter相当于一个UI库,所以使用前要引入flutter import 'package:flutter/material.dart'; // 入口函数 void main() => runApp(MyApp()); // 声明MyApp类 class MyApp extends StatelessWidget { // 重写build方法,它返回一个Material风格的组件 @override Widget build(BuildContext context) { // 在MaterialApp组件的home属性里赋值一个Scaffold组件 return MaterialApp( title: "welcome", home: Scaffold( // 在Scaffold组件(相当于脚手架的东西)里创建appBar和body appBar: AppBar(title: Text('This is header')), // 在body的中间区域添加hello world文本 body: Center(child: Text('hello world')), ), debugShowCheckedModeBanner: false,//去掉右上方的bug ); } }

效果: 精简版基本模板:

import 'package:flutter/material.dart'; void main()=>runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title:'test', home:Scaffold( appBar: new AppBar( title:new Text("这是头部"), ), body:new Text('内容') ) ); } }

也许你对上面的语法还不够了解,但你不必惊慌,我会进行说明,那先来看一下Dart中的函数。

Dart语法Function函数

Dart是面向对象的语言,即使是函数也是对象,并且属于函数类型的对象。 比如我们写的上面第二行代码,就是一个函数

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

上面是简写,普通写法如下:

void main() { return runApp(MyApp()); }

总结:发现Dart语言是不能省略结束符“;”的。

二.常用组件

Text()组件介绍

这个是文本组件,是非常常见的.记住在flutter中一切东西都是组件(组件英文名叫widget).

Text()组件的属性介绍:

textAlign文字对齐属性
center: 文本以居中形式对齐,这个也算比较常用的了。 left:左对齐,经常使用,让文本居左进行对齐,效果和start一样。 right :右对齐,使用频率也不算高。 start:以开始位置进行对齐,类似于左对齐。 end: 以为本结尾处进行对齐,不常用。有点类似右对齐.

总结起来,也就算三个对齐方式,left(左对齐)、center(居中对齐)、right(右对齐)。我们来看一下具体代码写法: 内容写在第一个参数里,属性以对象值的方式写.

maxLines属性最多显示的行数

maxLines属性设置显示的行数,比如我们给1,文字只能显示出1行了,多的自动消失.

overflow超出显示属性

有三个值: clip:直接切断, ellipsis:后面显示三个省略号, fade:直接切断,并带有整行上下渐变的效果. 注意值的写法是要加上Text,用TextOverflow点出各自的值.

style属性

style属性内容比较多:

inherit 是否将null值替换为祖先文本样式中的值(例如,在TextSpan树中)。如果为false,则没有显式值的属性将恢复为默认值:白色,字体大小为10像素,采用无衬线字体。 color 字体的颜色 fontSize 文字大小,单位为像素,如果没有指定大小则默认为14像素,可以乘以textScaleFactor来增加字体大小以便用户更加方便的阅读 fontWeight 字体厚度,可以使文本变粗或变细 fontStyle 字体变形,有两种 FontStyle.normal(字体直立), FontStyle.italic(字体倾斜) letterSpacing 字母间距,整数拉开字母距离,若是负数则拉近字母距离 wordSpacing,单词间距,同上 textBaseline 用于对齐文本的水平线 height 文本行高,为字体大小的倍数 locale 用于选择区域特定符号的区域设置 background 文本的背景颜色 shadows 文本的阴影可以利用列表叠加处理,例如shadows: [Shadow(color:Colors.black,offset: Offset(6, 3), blurRadius: 10)], color即阴影的颜色, offset即阴影相对文本的偏移坐标,blurRadius即阴影的模糊程度,越小越清晰 decoration 文字的线性装饰,比如 underline 下划线, lineThrough删除线 decorationColor 文本装饰线的颜色 decorationStyle 文本装饰线的样式,比如 dashed 虚线 debugLabel 这种文本样式的可读描述,此属性仅在调试构建中维护。

具体的可以看官网:https://api.flutter.dev/flutter/painting/TextStyle-class.html#painting.TextStyle.1

小技巧快速打开虚拟机的方法:依次点击下面的即可

Container组件的使用

Container组件相当于我们的div标签,它的作用就是方便我们进行布局的.

alignment属性

alignment属性的作用是针对的是Container内child的对齐方式,也就是容器子内容的对齐方式,并不是容器本身的对齐方式. 常用属性有:

bottomCenter:下部居中对齐。 botomLeft: 下部左对齐。 bottomRight:下部右对齐。 center:纵横双向居中对齐。 centerLeft:纵向居中横向居左对齐。 centerRight:纵向居中横向居右对齐。 topLeft:顶部左侧对齐。 topCenter:顶部居中对齐。 topRight: 顶部居左对齐。

总结规律:纵向在前,横向在后.

宽width,高height,背景颜色color(注意color不是字体颜色,而是背景颜色)设置

padding和margin属性

跟我们的css样式一样,但注意点写法:值是要带常量声明

padding:const EdgeInsets.all(20.0)

这句的意思是设置Container的内边距是20,左右上下全部为20,这看起来非常容易。那我们再加大一点难度。如果上边距为30,左边距为10,这时候EdgeInsets.all()就满足不了我们了。 我们用EdgeInsets.fromLTRB(value1,value2,value3,value4) 可以满足我们的需求,LTRB分别代表左、上、右、下。

decoration修饰属性

背景设置: decoration属性主要是用来设置背景和边框. 比如我们要设置渐变背景,上面的color背景只能设置单一颜色,我们可以用decoration来设置(与color不能同时存在,只能留一个) 设置方法:这时候就要用new BoxDecoration()这个组件.写法如下: 边框设置:(这个不需要new)

border:Border.all(width:2.0,color:Colors.purple)

效果: 附完整代码:

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

遇到的坑点:记住color背景属性和decoration属性不能同时存在,存在会报错.

Image图片组件

图片引入的几种方式:
Image.asset:加载资源图片,就是加载项目资源目录中的图片,加入图片后会增大打包的包体体积,用的是相对路径。 Image.network:网络资源图片,意思就是你需要加入一段http://xxxx.xxx的这样的网络路径地址。 Image.file:加载本地图片,就是加载本地文件中的图片,这个是一个绝对路径,跟包体无关。 Image.memory: 加载Uint8List资源图片(相当于内存一样),这个我目前用的不是很多.
图片fit填充属性的设置

填充属性值有以下几种:

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

color:是要混合的颜色,如果你只设置color是没有意义的。 colorBlendMode:是混合模式,相当于我们如何混合

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

repeat图片重复属性

ImageRepeat.repeat : 横向和纵向都进行重复,直到铺满整个画布。

ImageRepeat.repeatX: 横向重复,纵向不重复。

ImageRepeat.repeatY:纵向重复,横向不重复。

ListView列表循环组件

下面我们使用了ListView,然后在他的内部children中,使用了widget数组,因为是一个列表,所以它接受一个数组,然后有使用了listTite组件(列表瓦片),在组件中放置了图标和文字。 上面默认就是纵向列表,怎样变为横向列表你,在ListView组件里,设置scorllDirectin属性值为Axis.horizontal即可. 上面内容不能写死,怎样使用动态列表呢? 用dart语言准备数组,数组的声明方式有以下几种方式:

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

我声明和接收如下 使用后显示如下:

GridView网格列表组件

// 网格布局的基本使用 import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'GridView', home: Scaffold( body: GridView.count( padding: const EdgeInsets.all(20.0), crossAxisSpacing: 10.0, crossAxisCount: 3, //每行显示的列数 children: <Widget>[ Icon(Icons.ac_unit), Icon(Icons.airport_shuttle), Icon(Icons.all_inclusive), Icon(Icons.beach_access), Icon(Icons.cake), Icon(Icons.free_breakfast) ], ))); } }

常用属性:

padding:表示内边距,这个应该很熟悉。 crossAxisSpacing:网格间的空当,相当于每个网格之间的间距。 crossAxisCount:网格的列数,相当于一行放置的网格数量。

GridView用来图片布局: 注意第一个gridDelegate属性,它有两个参数,如下所示,第一个表示以数量布局,第二个表示以内容布局. 具体使用如下:

//图片布局 import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'GridView', home: Scaffold( body: GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 2.0, crossAxisSpacing: 2.0, childAspectRatio: 0.7), children: <Widget>[ new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2571762536.webp'), new Image.network( 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2567998580.webp'), new Image.network( 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2567998580.webp'), new Image.network( 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2567998580.webp'), ], ))); } }

效果:

说明: childAspectRatio:是宽高比,这个值的意思是宽是高的多少倍,如果宽是高的2倍,那我们就写2.0,如果高是宽的2倍,我们就写0.5。

三.布局

水平布局Row的使用

Row控件就是水平控件,它可以让Row里边的子元素进行水平排列,Row控件可以分为不灵活排列和灵活排列两种.

不灵活排列(默认)

从字面上就可以理解到,不灵活就是根据Row子元素内容的大小,进行布局。如果子元素内容不足,它会留有空隙,如果子元素内容超出,它会警告.

import 'package:flutter/material.dart'; void main(){ runApp(MyApp()); } class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title:"Row布局", home:Scaffold( appBar: AppBar(title:Text('头部')), body:Row( children:<Widget>[ RaisedButton( child:Text('蓝色按钮'), color:Colors.lightBlue, onPressed:(){} ), RaisedButton( child:Text('红色按钮'), color:Colors.redAccent, onPressed:(){} ), RaisedButton( child:Text('黄色按钮黄色按钮黄色按钮黄色按钮黄色按钮黄色按钮'),//文字超出会警告 color:Colors.orangeAccent, onPressed: (){}, ) ] ) ) ); } }

小坑:如果按钮不写onPressed属性,背景颜色不会出来. 效果: 假设上面"黄色按钮""只留四个字,那会出现下面没有充满的情况, 怎么让它刚好充满呢,这就用到我们的灵活布局了.

灵活布局

灵活布局只要在按钮的外边加入Expanded就可以,它会自动填充一屏.

import 'package:flutter/material.dart'; void main(){ runApp(MyApp()); } class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title:'切换文字', home:Scaffold( appBar:AppBar(title:Text("灵活水平布局")), body:Row( children: <Widget>[ RaisedButton( child: Text("蓝色按钮"), color:Colors.lightBlue, onPressed: (){}, ), Expanded( child:RaisedButton( child:Text('红色按钮'), color:Colors.redAccent, onPressed: (){}, ) ), Expanded( child:RaisedButton( child:Text('黄色按钮'), onPressed:(){}, color:Colors.orangeAccent ) ) ], ) ) ); } }

灵活水平布局和不灵活水平布局可以互相结合使用.

Column垂直布局的使用

// 垂直布局 import 'package:flutter/material.dart'; void main (){ runApp(MyApp()); } class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title:'', home:Scaffold( appBar:AppBar(title:Text('垂直布局')), body:Column( mainAxisAlignment:MainAxisAlignment.center,//主轴 crossAxisAlignment: CrossAxisAlignment.start,//副轴 children: <Widget>[ Text('第一行第一行第一行'), Expanded( child: Text('第二行'),//这里自适应 ) , Text('第三行第三行第三行第三行第三行第三行第三行') ], ) ) ); } }

Stack,Positioned层叠布局的使用

水平布局和垂直布局确实很好用,但是有一种情况是无法完成的,比如放入一个图片,图片上再写一些字或者放入容器,这时候Row和Column就力不从心了。Flutter为这种情况准备了Stack层叠布局.

import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '', home: Scaffold( appBar: AppBar( title: Text("Stack层叠布局"), ), body: Center( child: new Stack( alignment: const FractionalOffset(0.5, 0.8), children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage( 'https://avatars1.githubusercontent.com/u/45531884?s=460&v=4'), radius: 100.0, ), new Container( decoration: new BoxDecoration(color: Colors.lightBlue), padding: EdgeInsets.all(5.0), child: new Text('我是层叠文本')) ], )))); } }

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

CircleAvatar头像组件:这个经常用来做头像,组件里边有个radius的值可以设置图片的弧度。

Stack层叠的Position属性

当背景上层叠的组件超过两个时,我们可以考虑用Position定位属性,层叠定位无需alignment属性,直接给定位设置对应定位的坐标即可,操作如下:

import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '', home: Scaffold( appBar: AppBar( title: Text("Stack层叠布局"), ), body: Center( child: new Stack(children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage( 'https://avatars1.githubusercontent.com/u/45531884?s=460&v=4'), radius: 100.0, ), new Positioned( top:10.0, left:40.0, child:Text('定位内容1') ), new Positioned( right: 50.0, bottom: 20.0, child:Text('定位内容2') ) ])))); } }

Positioned组件的位置属性

bottom: 距离层叠组件下边的距离 left:距离层叠组件左边的距离 top:距离层叠组件上边的距离 right:距离层叠组件右边的距离 width: 层叠定位组件的宽度 height: 层叠定位组件的高度

Card卡片组件布局

这个布局可以做出很炫的东西,比如我们现在要开发一个类似收获地址的列表,并且列表外部使用一个卡片式布局,代码如下:

// 卡片布局 import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '', home: Scaffold( appBar: AppBar(title: Text('card布局')), body: Center( child: new Card( child: Column( //定义垂直布局 children: <Widget>[ ListTile(//每个瓦片 title: Text("广东省深圳市龙华区", style: TextStyle(fontWeight: FontWeight.w600)), //标题 subtitle: Text('电话:13800138000'), //第二行标题 leading: Icon(Icons.account_box, color: Colors.red) //左边内容 ) , new Divider(),//增加边框 ListTile( title:Text("广东省深圳市龙华区广东省深圳市龙华区",style:TextStyle(fontWeight:FontWeight.w600)), subtitle: Text('电话:13800138000'), leading:Icon(Icons.add_location,color:Colors.lightBlue) ), new Divider(color:Colors.red), ListTile( title:Text("广东省深圳市龙华区广东省深圳市龙华区",style:TextStyle(fontWeight:FontWeight.w600)), subtitle: Text('电话:13800138000'), leading:Icon(Icons.add_location,color:Colors.lightBlue) ), new Divider(color:Colors.blue) ], ), )))); } }

四.路由导航

1.页面跳转的应用:

导航的使用在任何程序里都至关重要,这也是一个程序的灵魂.下面先来一个一般页面的导航和返回,代码如下:

import 'package:flutter/material.dart'; void main(){ runApp( MaterialApp( title:'路由导航', home:new FirstScreen() ) ); } class FirstScreen extends StatelessWidget{ @override Widget build(BuildContext context){ return Scaffold( appBar:AppBar(title:Text('点击下面跳转查看详情页面')), body:Center( child: new RaisedButton( child:Text("去详情页面"), onPressed:(){ Navigator.push(context, MaterialPageRoute(builder:(context){ return SecondScreen(); }) ); } ), ) ); } } class SecondScreen extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( home:Scaffold( appBar: AppBar(title:Text("这是详情页")), body:Center( child: RaisedButton( child:Text('返回上一页'), onPressed:(){ Navigator.pop(context);//返回上一页,直接调用pop方法,把上下文传过去即可 } ) ) ) ); } }

路由的Navigator.push()和Navigator.pop()方法说明: Navigator.push():是跳转到下一个页面,它接收两个参数,参数1是上下文,参数2是MaterialPageRoute()组件,里面有一个builder属性,值是一个函数,参数是上下文,内容是要跳转的页面组件即可. 实现效果:

2.页面跳转的参数传递

import "package:flutter/material.dart"; // 准备一个商品信息的抽象类 class Product{ final String title;//商品标题 final String description;//商品描述 Product(this.title,this.description); } void main(){ runApp(MaterialApp( title:"参数传递案例", home:ProductList( // 下面是相当于声明了一个数组 products:List.generate(50,(index)=> Product('商品$index','这是商品详情,编号为$index') ), ) )); } class ProductList extends StatelessWidget{ final List<Product> products;// 引入上面的数组 ProductList({Key key,@required this.products}):super(key:key);//挂载在当前组件上,除了this.products,其它是固定写法 @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)=>ProductDetail(product:products[index])//括号里的是传递值 )); }, ); }, ) ); } } class ProductDetail extends StatelessWidget{ //接收上面传递的值 final Product product; //二三是抽象类和上面传递的属性 ProductDetail({Key key,@required this.product}):super(key:key); @override Widget build(BuildContext context){ return Scaffold( appBar: AppBar(title:Text(product.title)), body:Center(child: Text(product.description),) ); } }

说明:在点击商品列表的时候,我们用product属性将里面的products(商品信息,里面有标题和描述)传递了出去,在ProductDetail页面组件中进行了接收和使用.

实现效果:

3.返回页面携带参数
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp(title: '返回页面参数传递', home: FirstPage())); } class FirstPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("找小姐姐的电话")), body: Center( child: RouteButton())); } } class RouteButton extends StatelessWidget{ @override Widget build(BuildContext context){ return RaisedButton( child: Text('去找小姐姐'), onPressed: () { //下面这里调用异步请求,把上下文传递过去 _navigateToXiaoJieJie(context); }, ); } //在组件里准备异步请求函数,里面也是两个上下文方法,大括号前记得写async _navigateToXiaoJieJie(BuildContext context) 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) { return Scaffold( appBar: AppBar(title: Text("请选择你要的小姐姐")), body: Center( child: Column( children: <Widget>[ RaisedButton( child: Text("大长腿小姐姐"), onPressed: () { Navigator.pop(context, "大长腿电话:1511008888"); }, ), RaisedButton( child: Text("小长腿小姐姐"), onPressed: () { Navigator.pop(context, "小长腿电话:1511009999"); }, ), ], ))); } }

效果: 最后,附上源码链接地址:git@github.com:huanggengzhong/flutter.git

最新回复(0)