跨平台移动开发工具。
看了一些大佬的博客,我也试图收录一些对flutter 的语法、跨平台属性进行深入探索与总结
Image.asset(name);//从资源中获取图片
Image.file(file);//从文件中获取图片
Image.memory(bytes);//从内存中获取图片
Image.network(src);//从网络中获取图片
TextField有很多属性
decoration属性介绍: border:增加一个边框, hintText:未输入文字时,输入框中的提示文字, prefixIcon:输入框内侧左面的控件, labelText:一个提示文字。输入框获取焦点/输入框有内容 会移动到左上角,否则在输入框内,labelTex的位置. suffixIcon: 输入框内侧右面的图标. icon : 输入框左侧添加个图标
监听文本变化
监听文本变化有两种方式,一种是设置onChange回调,一种是controller监听,onChange专用于监听文本变化,controller还可以使用默认值,选择文本等,通常使用第二种
TextEditingController _selectionController = TextEdittingController()//创建controller
//创建监听
void initState() {
_selectionController.addlistener(){
print(_selectionController.text);
}
}
//设置默认值,并选中字符
_selectionController.text="helloworld";
_selectionController.selection = TextSelection(
baseOffset: 2,
extentOffset: _selectionController.text.length;//动态获取前两个字符之后的长度
)
//设置controller
TextField(
controller: _selectionController,
)
控制焦点
Text用于显示简单文本,具有文本样式控制属性
textAlign:文本的对齐方式,可以选择居中、左侧或者右侧
maxlines、overflow:指定文本显示的最大行数。如果有多余的文本,可以通过overflow指定截断方式。
textScaleFactor:代表文本相对于当前字体的缩放因子。相当于调整样式的字体大小属性,但是是根据系统字体大小全局调整而不是指定某段字体具体大小
Text("helloworld"*6//字符串重复6次
textAlign: TextAlign.center,//居中
maxLines: 1,//最大行数一行
overflow: TextOverflow.ellipsis,//多余的文本以省略号显示
textScaleFactor: 1.5,//默认为1
);
Textstyle用于指定文本显示的样式如颜色、字体、粗细、背景等
Text("helloworld"
style: TextStyle(
color: Colors.blue,//颜色
fontSize: 18.0,//大小
height: 1.2, //行高
fontFamily: "Courier",//字体
background: new Paint()..color=Colors.yellow,//背景颜色
decoration:TextDecoration.underline,//下划线
decorationStyle: TextDecorationStyle.dashed
),
);
Textspan对一个text中的字体进行不同样式的显示
在 Flutter 里有很多的 Button,包括了:MaterialButton、RaisedButton、FloatingActionButton、FlatButton、IconButton、ButtonBar、DropdownButton 等。
MaterialButton 是一个 Materia 风格的按钮。
RaisedButton 与 MaterialButton 类似
OutlineButton是一个有默认边线且背景透明的按钮,也就是说我们设置其边线和颜色是无效的,其他属性跟MaterialButton中属性基本一致
FlatButton 与 MaterialButton 类似,不同的是它是透明背景的。如果一个 Container 想要点击事件时,可以使用 FlatButton 包裹,而不是 MaterialButton。因为 MaterialButton 默认带背景,而 FlatButton 默认不带背景。
IconButton 顾名思义就是 Icon + Button 的复合体,当某个 Icon 需要点击事件时,使用 IconButton 最好不过。
FloatingActionButton 是一个浮动在页面右下角的浮动按钮。
ButtonBar 是一个布局组件,可以让 Button 排列在一行。
**DropdownButton ** 是下拉菜单按钮
https://www.jianshu.com/p/2f887cadd527
按钮button样式实例
//基本样式
RaisedButton(
onPressed: _log,//点击回调事件
child: Text("浮动按钮"),//按钮显示的文本
color: Colors.red,//按钮的主颜色
textColor: Colors.white,//按钮文本的颜色
splashColor: Colors.black,//点击按钮时水波纹的颜色
highlightColor: Colors.green,//长按按钮后显示的颜色
elevation: 30,//按钮下显示的阴影,一般设置小一点
shape: BeveledRectangleBorder(//边框形状,带斜角的长方形边框
side: BorderSide(
color: Colors.white,
),
borderRadius: BorderRadius.all(Radius.circular(10))
),
);
//其他边框形状
shape: CircleBorder(//圆形边框
side: BorderSide(
color: Colors.white,
),
),
shape: RoundedRectangleBorder(//圆角矩形边框
borderRadius: BorderRadius.all(Radius.circular(10)),
),
shape: StadiumBorder(),//两边是半圆的边框
浮动按钮组
floatingActionButton: ButtonBar(
// alignment 属性用来指定子元素如何在横轴上进行排列
// MainAxisAlignment.spaceAround 表示分散对齐,浮动按钮默认是靠右侧堆叠
alignment: MainAxisAlignment.spaceAround,
// 子元素
children: <Widget>[
// 第一个浮动按钮
FloatingActionButton(
onPressed: () {
choosePic(ImageSource.camera);
},
tooltip: 'takephoto',
child: Icon(Icons.photo_camera),
),
// 第二个浮动按钮
FloatingActionButton(
onPressed: () {
choosePic(ImageSource.gallery);
},
tooltip: 'takepicture',
child: Icon(Icons.photo_library),
)
],
)
安装包
dependencies:
flutter_speed_dial: ^1.2.4
引入包
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
实例
线性布局是指水平方向和垂直方向。
线性布局有主轴和纵轴之分。水平方向布局中,主轴为水平方向,纵轴为垂直方向
垂直方向布局中,主轴为垂直方向,纵轴为水平方向。
Row在水平方向排列其子组件widget,Column在垂直方向排列其子组件widget
具体方法
textDirection:水平方向子组件的布局顺序。默认为中文、英文从左向右,阿拉伯语从右向左。指定赋值时,.ltr表示从左向右,.rtl表示从右向左
verticalDirection: Row自身在纵轴的对齐方式,默认为.down为从上到下
maxnAxisSize: 表示Row在水平方向的占用空间。max为尽可能多的占用水平空间,此时Row的宽度始终等于水平方向最大宽度,min为尽可能少的占用水平空间,此时Row的宽度为所有子组件占用的水平空间。
mainAxisAlignment:子组件在主轴上的对齐方式。Row中为水平方向,Column中为垂直方向 。值有.start 表示从textDirection指定的方向首端.center 居中对齐 .end 表示从textDirection指定的方向尾端,.spacebetween
crossAxisAlignment: 子组件在纵轴上的对齐方式。Row中为垂直方向,Column中为水平方向。值有.start 表示从verticalDirection指定的方向首端.center 居中对齐.end 表示从verticalDirection指定的方向尾端, .spacebetween
crossAxisAlignment: 子组件在纵轴上的对齐方式。Row中为垂直方向,Column中为水平方向
children: 子组件
实例
Expanded可以按比例扩伸Row、Column。
Padding为子节点控制边距,通常使用Padding中的EdgeInsets类,其中定义了一些设置边距的便捷方法
EdgeInsets中的方法:
实例
class PaddingTest extends statelessWidget {
Widget build(BuildContext context) {
return Padding(
//上下左右添加相同16像素边距
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget> [
Padding(
//左侧添加8像素边距
padding: const EdgeInsets.only(left: 8.0),
child: Text("Helloworld"),
),
Padding(
//上下对称添加8像素边距
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text("Helloworld"),
),
Padding(
//指定四个方向的边距
padding: const EdgeInsets.fromLTRB(20.0,0,20.0,8.0),
child: Text("Helloworld"),
),
],
),
);
}
}
装饰器可以向子组件添加一些特殊样式,如背景、边框,渐变等。使用时一般使用子类BoxDecoration,实现常用元素的装饰绘制
具体
color、//颜色 image//图片、border//边框,borderRadius//圆角,
boxShadow//阴影,gradient//渐变、 boxshape//形状、backgroundBlendMode//背景混合模式
实例
Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors:[Colors.red,Colors.orange[700]]),//背景渐变
borderRadius: BorderRadius: circular(3.0),//3像素圆角
boxShadow: [//阴影
BoxShadow(
color:Colors.black54,
offset: Offset(2.0,2.0),
blurRadius: 4.0,
)
]
child: Text("login",style: TextStyle(color: Colors.white),),
)
)
return stack
参数:
physics: 此对象接受一个ScrollPhysics类型的对象,用以滚动组件如何响应用户操作,比如抬起手指之后继续执行动画,滑动到底部时如何显示。默认情况下flutter会根据平台显示不同效果。
shrinkWrap:是否根据子组件的总长度设置Listview的长度,默认为false,也就是默认情况下Liseview会尽可能地占用较多空间
controller:此对象接受一个ScrollController对象,控制滚动位置和监听滚动事件。ScrollController常用属性和方法:
offset:可滚动组件当前的滚动位置
jupmTo(double offset)、animateTo(double offset):这两个方法用于跳转到指定位置,后者会执行一个动画而前者不会
reverse: 是否与滑动方向相反,默认为false
itemExtent:滚动为垂直方向时为子组件的高度,滚动为水平方向时为子组件的宽度
列表项不多时使用ListView,用构造函数中的children参数
ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children:<Widget>[
const Text('i am'),
const Text('i am'),
const Text('i am'),
const Text('i am'),
],
);
ListView.builder方法适用于列表项比较多的情况,该方法创建子组件时只有子组件真正显示时才会被创建,也就是基于Sliver的懒加载模型
参数:
itemCount:指定列表项的数目,null为无限
itemBuilder:列表项构造器
ListView.seperated方法可以在生成的列表之间添加一个分割组件,它比Listview.builder多了一个separatorbuilder的参数,该参数可以生成一个分割组件生成器。
//创建一个奇数行蓝色下划线,偶数行绿色下划线的列表
class ListView extends StatelessWidget {
Widget build(BuildContext context){
Widget divide1= Divider(color: Colors.blue,);
Widget divide2= Divider(color: Colors.green,);
return ListView.separated(
itemCount: 100,
itemBuilder: (BuildContext context,int index){
return ListTile(title: Text("$index"));
},
separatorBuilder: (BuildContext context,int index){
return index$2==0?divider1:divider2;
},
);
}
}
Gridview可以构造二维网格列表
主要参数:
crossAxisCount:横轴子元素的数量
mainAxisSpacing:主轴方向的间距
crossAxisSpacing:横轴方向子元素的间距
childAspectRatio:子元素在横轴长度和主轴长度的比例。一般由crossAxisCount指定子元素的横轴长度,再通过此参数确定子元素的主轴长度
Gridview.count 创建横轴固定数量子元素的gridview,内部包含SliverGridDelegateWithFixedCrossAxisCount类
GridView.extent(
crossAxisCount: 3,//子元素数量为3
childAspectRatio: 1.0,//宽高比为2
children: <Widget>[
Icons(Icons.ac_unit),
Icons(Icons.airport_shuttle),
Icons(Icons.all_inclusive),
Icons(Icons.beach_access),
Icons(Icons.cake),
Icons(Icons.free_breakfast),
],
);
Gridview.extent 创建纵轴子元素为固定长度的gridview,内部包含SliverGridDelegateWithMaxCrossAxisExtent类,
GridView.extent(
maxCrossAxisExtent: 120.0,//子元素在横轴上的最大长度
childAspectRatio: 2.0,//宽高比为2
children: <Widget>[
Icons(Icons.ac_unit),
Icons(Icons.airport_shuttle),
Icons(Icons.all_inclusive),
Icons(Icons.beach_access),
Icons(Icons.cake),
Icons(Icons.free_breakfast),
],
);
Gridview.builder 当子组件较多时通过Gridview.builder动态创建子widget,使用ItemBuilder创建子widget
当一个页面同时使用gridview和listview时,由于两个组件相互独立,不能保证他们滚动效果一致,因此需要一个粘合剂使他们成为一体,使用CustomScrollView
return Material(
child: CustomScrollView(
slivers: <Widget>[
//AppBar,包含一个导航栏
SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: const Text('Demo'),
background: Image.asset(
"./images/avatar.png", fit: BoxFit.cover,),
),
),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: new SliverGrid( //Grid
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //Grid按两列显示
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
//创建子widget
return new Container(
alignment: Alignment.center,
color: Colors.cyan[100 * (index % 9)],
child: new Text('grid item $index'),
);
},
childCount: 20,
),
),
),
new SliverFixedExtentList(
itemExtent: 50.0,
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
//创建列表项
return new Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: new Text('list item $index'),
);
},
childCount: 50 //50个列表项
),
),
],
安装包
dependencies:
pull_to_refresh: ^1.6.0
引入包
import 'package:pull_to_refresh/pull_to_refresh.dart';
实例
RefreshController _refreshController =
RefreshController(initialRefresh: false);
void _onRefresh() async{
// monitor network fetch
await Future.delayed(Duration(milliseconds: 1000));
// if failed,use refreshFailed()
_refreshController.refreshCompleted();
}
void _onLoading() async{
// monitor network fetch
await Future.delayed(Duration(milliseconds: 1000));
// if failed,use loadFailed(),if no data return,use LoadNodata()
items.add((items.length+1).toString());
if(mounted)
setState(() {
});
_refreshController.loadComplete();
}
Widget build(BuildContext context) {
return Scaffold(
body: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
header: WaterDropHeader(),
footer: CustomFooter(
builder: (BuildContext context,LoadStatus mode){
Widget body ;
if(mode==LoadStatus.idle){
body = Text("上拉加载");
}
else if(mode==LoadStatus.loading){
body = CupertinoActivityIndicator();
}
else if(mode == LoadStatus.failed){
body = Text("加载失败!点击重试!");
}
else if(mode == LoadStatus.canLoading){
body = Text("松手,加载更多!");
}
else{
body = Text("没有更多数据了!");
}
return Container(
height: 55.0,
child: Center(child:body),
);
},
),
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: ListView.builder(
itemBuilder: (c, i) => Card(child: Center(child: Text(items[i]))),
itemExtent: 100.0,
itemCount: items.length,
),
),
);
}
可以自定义上拉或下拉刷新加载样式,
下拉样式 RefreshStyle.Follow,RefreshStyle.UnFollow,RefreshStyle.Front,RefreshStyle.Behind
上拉样式 LoadStyle.ShowAlways,LoadStyle.HideAlways,LoadStyle.ShowWhenLoading
全局配置RefreshConfiguration用于配置子树下的所有智能刷新器表示形式,通常存储在MaterialApp的根目录下,其用法与ScrollConfiguration类似.
// 全局配置子树下的SmartRefresher,下面列举几个特别重要的属性
RefreshConfiguration(
// 如果每个页面的头部指示器都一样的话,可以设置默认头部指示器
headerBuilder: () => WaterDropHeader(),
// 配置默认底部指示器
footerBuilder: () => ClassicFooter(),
headerTriggerDistance: 80.0, // 头部触发刷新的越界距离
// 自定义回弹动画,三个属性值意义请查询flutter api
springDescription:SpringDescription(stiffness: 170, damping: 16, mass: 1.9),
maxOverScrollExtent :100, //头部最大可以拖动的范围,如果发生冲出视图范围区域,请设置这个属性
maxUnderScrollExtent:0, // 底部最大可以拖动的范围
//这个属性不兼容PageView和TabBarView,如果你特别需要TabBarView左右滑动,你需要把它设置为true
enableScrollWhenRefreshCompleted: true,
enableLoadingWhenFailed : true, //在加载失败的状态下,用户仍然可以通过手势上拉来触发加载更多
hideFooterWhenNotFull: false, // Viewport不满一屏时,禁用上拉加载更多功能
enableBallisticLoad: true, // 可以通过惯性滑动触发加载更多
child: MaterialApp(
........
)
);
国际化,根据App语言显示下拉文字为中文或英文
MaterialApp(
localizationsDelegates: [
// 这行是关键
RefreshLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalMaterialLocalizations.delegate
],
supportedLocales: [
const Locale('en'),
const Locale('zh'),
],
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
//print("change language");
return locale;
},
)
https://github.com/felangel/bloc
bloc是一个典型的观察者模式,我们以counter bloc举例,在A,B页面都存在观察者,它们监听的是同一个广播流,当我们pop B页面,回到A页面这个操作不会出现任何问题,而当我们再次进入B页面的时候却发现,它显示了初始值0,而不是我们想要的value,只有等我们再次按下按钮时,它才能刷新获得实际的value。
ReactiveX的dart 实现——RxDart,它极大的扩展了Stream的功能,能够让我们在使用bloc的时候更加游刃有余。