-
有状态widget:StatefulWidget和无状态widget:StatelessWidget 前者不需要实现Widget build(BuildContext context)。
具体的选择取决于widget是否需要管理一些状态
在Dart语言中使用下划线前缀标识符,会强制其变成私有的。
Icons.favorite Icons类里面有很多默认图标
isOdd 是否奇数 2.isOdd -> false 1.isOdd -> true
pushSaved “”开头的自动转成私有(方法和变量)
导航栏添加按钮和事件
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Startup Name Generator'),
actions: [
// AppBar 添加一个按钮 样式为list 事件是_pushSaved
new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved)
],
),
body: _buildSuggestions(),
);
}
// tooltip 长时间按下的提示文字
IconButton(icon: new Icon(Icons.search), tooltip: 'Search', onPressed: null)
- 界面跳转方法
Navigator.of(context).push(
new MaterialPageRoute(
builder: (context) {
},
),
);
- 一行函数写法
// 多行
void main() {
runApp(
new Center(
child: new Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
)
)
}
// 一行
void main() => runApp(new MyApp());
// Material 是UI呈现的“一张纸”
请确保在pubspec.yaml文件中,将flutter的值设置为:uses-material-design: true。这允许我们可以使用一组预定义Material icons。
Row(横向排列)和Column(纵向排列)
child: new Row(
children: [
new ...,
new ...,
new ...,
],
)
child: new Column(
children: [
new ...,
new ...,
new ...,
],
),
cached_network_image 图片占位和淡入淡出
push
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new 新界面),
);
// 如果需要传值:
新界面({Key key, @required this.接收字段的名字}) : super(key: key);
pop
Navigator.pop(context);
dio网络请求 https://github.com/flutterchina/dio
import 'dart:convert'; // package将响应内容转化为一个json Map
// 使用fromJson工厂函数,将json Map 转化为一个Post对象
new Post.fromJson(json);
future参数是一个异步的网络请求
import 'dart:io'; // 添加请求的headers
// 长连接
import 'package:web_socket_channel/io.dart';
import 'package:multi_server_socket/multi_server_socket.dart';
- // 网络请求
Future fetchPost() async {
final response = await http.get('[http://jsonplaceholder.typicode.com/posts/1](http://jsonplaceholder.typicode.com/posts/1)');
final responseJson = json.decode(response.body);
return new Post.fromJson(responseJson);
}
// 请求添加headers
/*
Future fetchPost() async {
final response = await http.get(
'[https://jsonplaceholder.typicode.com/posts/1](https://jsonplaceholder.typicode.com/posts/1)',
headers: {HttpHeaders.AUTHORIZATION: "Basic your_api_token_here"},
);
final json = jsonDecode(response.body);
return new Post.fromJson(json);
}
*/
new FutureBuilder(
future: fetchPost(),
builder: (context, snapshot) {
return new CircularProgressIndicator();
}
)
- 长连接
// 连接长连接
IOWebSocketChannel.connect('[ws://echo](ws://echo/).[websocket.org](http://websocket.org/)’)
// 接收消息
new StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot) {
return new Padding(
child: new Text(snapshot.hasData ? '${snapshot.data}' : ''),
padding: const EdgeInsets.symmetric(vertical: 20.0)
);
}
)
// 发送消息
widget.channel.sink.add(_textController.text);
// 关闭长连接
widget.channel.sink.close();
- 在Flutter中添加资源和图片
https://flutterchina.club/assets-and-images/
- 标准widget:
Container
添加 padding, margins, borders, background color, 或将其他装饰添加到widget.
GridView
将 widgets 排列为可滚动的网格.
ListView
将widget排列为可滚动列表
Stack
将widget重叠在另一个widget之上.
Material Components:
Card
将相关内容放到带圆角和投影的盒子中。
ListTile
将最多3行文字,以及可选的行前和和行尾的图标排成一行
- pubspec.yaml中添加字体 注意缩进对齐 注意缩进对齐 注意缩进对齐
-asset 路径是与pubspec.yaml平级的文件路径
flutter:
# Include the Material Design fonts.
uses-material-design: true
fonts:
- family: Rock Salt
fonts:
# [https://fonts.google.com/specimen/Rock+Salt](https://fonts.google.com/specimen/Rock+Salt)
- asset: fonts/Arial-Unicode.ttf
- family: VT323
fonts:
# [https://fonts.google.com/specimen/VT323](https://fonts.google.com/specimen/VT323)
- asset: fonts/Arial-Unicode.ttf
- family: Ewert
fonts:
# [https://fonts.google.com/specimen/Ewert](https://fonts.google.com/specimen/Ewert)
- asset: fonts/Ewert-Regular.ttf
- 比如一个关闭按钮在
new Row(mainAxisAlignment: MainAxisAlignment.end, children: [
new FlatButton(onPressed: () {
}, child: Icon(Icons.close))
],);
- 分割线
new Divider(color: Colors.lightBlue,)
- 自定义Icon
new Image.asset(“图片路径", width: 20.0, height: 20.0,)
- 按钮宽高
001、
new Padding(padding: new EdgeInsets.fromLTRB(48.0, 20.0, 48.0, 20.0),
child: new Row(
children: [
new Expanded(child:
new RaisedButton(onPressed: (){
},
//设置控件的高度
child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
child: new Text("登录",
style: TextStyle(color: Colors.white)
),
),
color: Colors.brown,
),
),
],
),
),
002、
new Container(
width: MediaQuery.of(context).size.width - 48 * 2 ,
padding: new EdgeInsets.only(top: 40.0),
child: new RaisedButton(onPressed: (){
},
//设置控件的高度
child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
child: new Text("登录",
style: TextStyle(color: Colors.white)
),
),
color: Colors.brown,
),
),
003、
Widget _bigButton(String text, double lSpace, double rSpace) {
return new Container(
width: MediaQuery.of(context).size.width - lSpace - rSpace,
height: 48.0,
margin: new EdgeInsets.only(left: lSpace, right: rSpace),
color: Colors.white54,
padding: new EdgeInsets.only(top: 0.0),
child: new RaisedButton(onPressed: (){
print(text);
},
child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: new Text(text,
style: TextStyle(color: Colors.white)
),
),
color: Colors.brown,
),
);
}
- 设备尺寸
MediaQuery.of(context).size.width
- 设备像素密度
MediaQuery.of(context).devicePixelRatio
- 状态栏高度
MediaQuery.of(context).padding.top
担心键盘挡住控件,可以使用 SingleChildScrollView,将SingleChildScrollView当做容器。
一个超级简单界面
import 'package:flutter/material.dart';
class RegisterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.black,
body: new RegisterWidget(),
);
}
}
class RegisterWidget extends StatefulWidget {
RegisterWidgetState createState() => RegisterWidgetState();
}
class RegisterWidgetState extends State {
@override
Widget build(BuildContext context) {
return new Text("RegisterPage", style: TextStyle(color: Colors.white),);
}
}
- Flutter 按钮总结
· InkWell // 纯文字按钮
· OutLineButton // 边框按钮
· IconButton // icon按钮
·
- import 'package:flutter/services.dart';
TextField
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly,
],
以上已经添加
验证码按钮
new Positioned(
child: new Container(
width: 80.0,
height: 27.0,
alignment: Alignment.center,
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.white,
width: 1.0,
),
borderRadius: new BorderRadius.circular(4.0),
),
child: InkWell(
child: _mText(_verifyStr, 12.0),
onTap: () {
},
),
)
),
- 倒计时方法
@override
void dispose() {
super.dispose();
_cancelTimer();
}
_startTimer() {
if (_verifyStr == '重新发送' || _verifyStr == '获取验证码') {
_seconds = 5;
_timer = new Timer.periodic(new Duration(seconds: 1), (timer) {
if (_seconds == 0) {
_cancelTimer();
return;
}
_seconds--;
_verifyStr = '$_seconds(s)';
setState(() {});
if (_seconds == 0) {
_verifyStr = '重新发送';
}
});
}
}
_cancelTimer() {
_timer?.cancel();
}
- 富文本拼接: 协议
Widget _protocolWidget() {
return new Container(
child: new Row(
children: [
new GestureDetector(
onTap: () {
print("选择");
},
child: Icon(Icons.add_alert, color: Colors.white),
),
new Text.rich(
new TextSpan(
text: '我已阅读并同意',
style: new TextStyle(
fontSize: 12.0,
color: Colors.grey[500],
fontWeight: FontWeight.w400,
),
children: [
new TextSpan(
recognizer: new TapGestureRecognizer()
..onTap = () {
print("《燎原用户服务协议》");
},
text: "《燎原用户服务协议》",
style: new TextStyle(
fontSize: 14.0,
color: Color(0XFFB57A36),
fontWeight: FontWeight.w400,
),
)
]
)
),
],
)
);
}
- 阴影、圆角
new Card(
elevation: 4.0,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
bottomLeft: Radius.circular(12.0),
bottomRight: Radius.circular(2.0),
)
),
child: new IconButton(icon: Icon(Icons.add), onPressed: () {
}),
)
- YYTabbarWidget
import 'package:flutter/material.dart';
// with AutomaticKeepAliveClientMixin
class YYTabbarWidget extends StatefulWidget {
List tabItems = [];
Widget title;
List tabViews = [];
PageController pageController;
final ValueChanged onPageChanged;
final Widget drawer;
YYTabbarWidget({Key key,
this.drawer,
this.tabItems,
this.title,
this.tabViews,
this.pageController,
this.onPageChanged,
}) : super(key: key);
_YYTabbarWidgetState createState() => _YYTabbarWidgetState(drawer, title, tabItems, tabViews, pageController, onPageChanged);
}
class _YYTabbarWidgetState extends State with SingleTickerProviderStateMixin {
final Widget _title;
final List _tabViews;
final List _tabItems;
final ValueChanged _onPageChanged;
final Widget _drawer;
_YYTabbarWidgetState(
this._drawer,
this._title,
this._tabItems,
this._tabViews,
this._pageController,
this._onPageChanged,
) : super();
TabController _tabController;
PageController _pageController;
@override
void initState() {
super.initState();
_tabController = new TabController(length: _tabItems.length, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
_renderTab() {
print(_tabItems);
List list = new List();
for (int i = 0; i < _tabItems.length; i++) {
list.add(new FlatButton(onPressed: () {
print(i);
_pageController.jumpTo(MediaQuery
.of(context)
.size
.width * i);
}, child: _tabItems[I],
)
);
}
return list;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
drawer: _drawer,
appBar: new AppBar(
title: _title,
),
body: new PageView(
controller: _pageController,
children: _tabViews,
onPageChanged: (index) {
_tabController.animateTo(index);
_onPageChanged?.call(index);
},
),
bottomNavigationBar: new Material(
color: Colors.white,
child: new TabBar(
indicatorPadding: new EdgeInsets.only(top: 0.0),
controller: _tabController,
tabs: _renderTab(),
indicatorColor: Colors.red,
),
),
);
}
}
- ListView 添加刷新,当数量少的时候不能滚动
physics: new AlwaysScrollableScrollPhysics(), // 让ListView一直可以滚动
- tabView切换 子界面都会调用initState
解决:AutomaticKeepAliveClientMixin
class HomePageState extends State with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
}
- 路有跳转
///不带参数的路由表跳转
Navigator.pushNamed(context,routeName);
///跳转新页面并且替换,比如登录页跳转主页
Navigator.pushReplacementNamed(context,routeName);
///跳转到新的路由,并且关闭给定路由的之前的所有页面
Navigator.pushNamedAndRemoveUntil(context,'/calendar',ModalRoute.withName('/'));
///带参数的路由跳转,并且监听返回
Navigator.push(context,newMaterialPageRoute(builder:(context)=>newNotifyPage())).then((res){
///获取返回处理
});
- flutter lib
cupertino_icons: ^0.1.2 #icon
flutter_spinkit: "^2.1.0" # load more loading import 'package:flutter_spinkit/flutter_spinkit.dart';
dio: x.x.x #无网络请求 import 'package:dio/dio.dart';
- dio网络请求示例
_dioRequest() async {
Dio dio = new Dio();
Response response;
try {
String url;
var params; // 请求参数
Options options; // 配置:超时,请求头,请求类型等
response = await dio.request(url, data: params, options: options);
} on DioError catch(e) {
// 请求出错时,返回一个DioError对象
}
}
- build_runner的使用
1、在根目录运行
2、一次性创建.g.dart文件 使用build 此时目录内不能有.g.dart文件
3、watch是监听 有model类的文件创建 自动创建.g.dart文件
flutter packages pub run build_runner build
flutter packages pub run build_runner watch