bash, mkdir, rm, git, curl, unzip, which
复制代码
flutter官网下载其最新可用的安装包git
安装包下载完成则能够进行解压github
unzip /指定解压目录/flutter_macos_v1.9.1+hotfix.4-stable.zip
复制代码
# 使用pwd 命令查看目录路径
/Users/XXXXX/development/flutter
复制代码
设置环境变量目的是以便咱们能够运行flutter命令在任何终端会话中算法
肯定Flutter SDK的目录,上一步咱们解压获取了flutter的路径/Users/XXXXX/development/fluttermacos
打开(或建立) HOME 指的是 路径是 /Users/用户名XX/ )编程
vim $HOME/.bash_profile
复制代码
export PUB_HOSTED_URL=https://pub.flutter-io.cn //国内用户须要设置
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //国内用户须要设置
//
export PATH=/Users/XXXXX/development/flutter/bin:$PATH
复制代码
source $HOME/.bash_profile
注意: 若是你使用的是zsh,终端启动时 ~/.bash_profile 将不会被加载,解决办法就是修改 ~/.zshrc ,在其中添加:source ~/.bash_profile
复制代码
flutter doctor
复制代码
flutter upgrade
复制代码
var name = 'maoqitian';
var number = 1;
复制代码
final List _suggestions = new List<WordPair>();
final _suggestions = <WordPair>[];
复制代码
//以下定义一个字体大小的值一直都是 18 ,不会改变
final _biggerFont = const TextStyle(fontSize: 18.0)
复制代码
//定义一个返回 bool(布尔)类型的方法
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//转换以下能够忽略类型定义
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//只有一个表达式的方法,你能够选择 使用缩写语法来定义
// => expr 语法是 { return expr; } 形式的缩写
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
复制代码
//调用有可选命名参数方法 playGames
playGames(bold: true, hidden: false);
//playGames 方法
playGames({bool bold, bool hidden}) {
// ...
}
复制代码
// 定义可选位置参数方法
String playGames (String from, String msg, [String sports]) {
var result = '$from suggest $msg';
if (sports != null) {
result = '$result playing $sports together';
}
return result;
}
// 不用可选参数
playGames('Bob', 'Howdy'); // 返回值 Bob suggest Howdy
//使用可选参数
playGames('I', 'Xiao Ming', 'basketball'); //返回值 I suggest Xiao Ming playing basketball together.
复制代码
// 定义可选位置参数方法
String playGames (String from , String msg, [String sports = 'football']) {
var result = '$from suggest $msg';
if (sports != null) {
result = '$result playing $sports together';
}
return result;
}
playGames('I', 'Xiao Ming'); //返回值 I suggest Xiao Ming playing football together.
复制代码
// Android studio 建立Demo 项目 main.dart 文件开头
void main() => runApp(MyApp());
//能够转换为
void main(){
runApp(MyApp());
}
复制代码
static Future<ArticleListData> getArticleData(int pageNum) async{
String path = '/article/list/$pageNum/json';
Response response = await HttpUtils.get(Api.BASE_URL+path);
ArticleBaseData articleBaseData = ArticleBaseData.fromJson(response.data);
return articleBaseData.data;
}
复制代码
先了解这么多,更多Dart 相关内容能够查看Dart语言官网json
在开始Flutter Hello world程序以前,做为一名Android 开发者,首先咱们要认识到Flutter中没有原生开发的XML,全部界面和逻辑代码都在.dart文件中,Flutter给我提供了一套视觉、结构、平台、和交互式的Widgets,因此在Flutter中一构架的一切界面都是Widgets。接下来咱们先看一个简单的Hello World Flutter应用。vim
Android Studio 新建Flutter demo数组
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
theme: ThemeData(
primaryColor: Colors.blueAccent,
),
home: new Scaffold(
appBar: new AppBar(
title: new Center(
child: new Text("Welcome to Flutter"),
)
),
body: DemoStatelessWidget("Flutter Hello World ! 无状态的Widget"),
),
);
}
}
//无状态 Widget
class DemoStatelessWidget extends StatelessWidget{
final String text;
//构造方法传入 text 值
DemoStatelessWidget(this.text);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
constraints: BoxConstraints.expand(
height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
),
padding: const EdgeInsets.all(8.0),
color: Colors.blue[600],
alignment: Alignment.center,
child: Text(text,
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.white)),
transform: Matrix4.rotationZ(0.1),
);
}
}
复制代码
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
// StatelessWidget 无状态的widget
class MyApp extends StatelessWidget { //Stateless widgets是不可变的, 这意味着它们的属性不能改变 - 全部的值都是最终的.
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Welcome to Flutter',
theme: ThemeData(
primaryColor: Colors.blueAccent,
),
home: new RandomWords(),
);
}
}
//StatefulWidget 有状态的widget
class RandomWords extends StatefulWidget{
@override
createState() => new RandomWordsState();
}
// 返回 显示单词对的ListView Widget
class RandomWordsState extends State<RandomWords> {
//保存建议的单词对列表(变量如下划线(_)开头,在Dart语言中使用下划线前缀标识符,会强制其变成私有的) final _suggestions = <WordPair>[];
final List _suggestions = new List<WordPair>();
//设置字体大小的变量
final _biggerFont = const TextStyle(fontSize: 18.0);
// 保存喜欢单词组的集合 set 集合不容许值重复
final Set _saved = new Set<WordPair>();
/// State 生命周期方法
@override
void initState() {
// state 初始化
super.initState();
}
@override
void didChangeDependencies() {
// 在 initState 以后调用,此时能够获取其余 State
super.didChangeDependencies();
}
@override
void dispose() {
// state 销毁
super.dispose();
}
@override
Widget build(BuildContext context) {
//return new Text(new WordPair.random().asPascalCase);
//返回单词对的ListView。
return new Scaffold(
appBar: new AppBar(
title:new Center( //居中显示
child: new Text('Flutter ListView'),
),
),
body: _buildSuggestions(),
);
}
//构建显示建议单词对的ListView。
Widget _buildSuggestions(){
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// 对于每一个建议的单词对都会调用一次itemBuilder,而后将单词对添加到ListTile行中
// 在偶数行,该函数会为单词对添加一个ListTile row.
// 在奇数行,该函数会添加一个分割线widget,来分隔相邻的词对。
//itemBuilder 值是一个匿名回调函数, 接受两个参数- BuildContext和行迭代器i。迭代器从0开始,
// 每调用一次该函数,i就会自增1,对于每一个建议的单词对都会执行一次。该模型容许建议的单词对列表在用户滚动时无限增加。
itemBuilder: (context,i){
// 在每一列以前,添加一个1像素高的分隔线widget
if(i.isOdd) return new Divider();
// 语法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),好比i为:1, 2, 3, 4, 5
// 时,结果为0, 1, 1, 2, 2, 这能够计算出ListView中减去分隔线后的实际单词对数量
final index = i~/2;
if(index >= _suggestions.length){
// 若是是建议单词列表中最后一个单词对 接着再生成10个单词对,而后添加到建议列表
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
}
);
}
//建立 ListTile中显示每一个新词对
Widget _buildRow(WordPair suggestion) {
//获取是否保存了该单词状态
final isSaved = _saved.contains(suggestion);
return new ListTile(
// 设置 标题
title: new Text(
suggestion.asPascalCase,
style: _biggerFont,
),
//图标
trailing: new Icon(
//星型图标状态
isSaved ? Icons.favorite : Icons.favorite_border,
color: isSaved ? Colors.deepOrange : null ,
),
onTap: (){ // 当用户点击 ListTile 击时, ListTile 会调用它的onTap回调
setState(() { //调用setState() 会为State对象触发build()方法,从而致使对UI的更新
if(isSaved){
_saved.remove(suggestion);
}else{
_saved.add(suggestion);
}
});
},
);
}
}
复制代码
如上代码,将原来的无状态Widget改为了StatefulWidget,并在build中构建ListView,到此你可能有疑惑,不是说有状态的Widget,怎么仍是建立Widget,有状态如何体现呢? 别急,咱们看到_buildRow方法,方法中构建了ListTile 这个Widget,它响应点击事件回到为onTap方法,也就是当咱们点击ListTile,咱们在onTap方法中就能够调用setState方法来动态改变页面显示,也就是改变桃心收藏按钮变化(注意setState方法须要在State类中才能调用)。bash
State 是有周期的,其中包括三个函数:网络
布局名称 | 特色描述 |
---|---|
Container | 拥有单个子元素的布局widget,能够灵活设置 |
Padding | 拥有单个子元素,给其子widget添加指定的填充 |
Center | 将其子widget居中显示 |
Align | 将其子widget对齐,并能够根据子widget的大小自动调整大小。 |
Row | 能够拥有多个子元素,在水平方向上排列子widget的列表,和原生控件 LinerLayout orientation="horizontal" 相似 |
Column | 能够拥有多个子元素,在竖直方向上排列子widget的列表,和原生控件 LinerLayout orientation="vertical" 相似 |
Stack | 能够拥有多个子元素,容许其子widget简单的堆叠在一块儿 |
Flow | 实现流式布局算法的widget |
ListView | 可滚动的列表控件 |
Widget名称 | 特色描述 |
---|---|
MaterialApp | 封装了应用程序实现Material Design所须要的一些widget,由前面demo能够发现它通常为应用顶层入口widget |
Scaffold | Material Design布局结构的基本实现。此类提供了用于显示drawer、snackbar和底部sheet的API。 |
Appbar | 通常和Scaffold结合使用,能够设置页面标题和各类按钮等(Toolbar) |
BottomNavigationBar | 底部导航条,能够很容易地在tap之间切换和浏览顶级视图 |
Drawer | 和Scaffold结合使用,从Scaffold边缘水平滑动以显示应用程序中导航连接的Material Design面板 |
RaisedButton | Material Design中的button,响应点击事件(button) |
IconButton | 一个Material图标按钮,能够设置icon,点击时会有水波动画 |
TextField | 文本输入框 (EditText) |
image | 显示图片的widget(ImageView) |
Text | 单一格式的文本 (TextView) |
import 'package:flutter/material.dart';
class AppPage extends StatefulWidget {
@override
_AppPageState createState() => _AppPageState();
}
class _AppPageState extends State<AppPage> {
@override
Widget build(BuildContext context) {
return WillPopScope( ///经过WillPopScope 嵌套,能够用于监听处理 Android 返回键的逻辑。 WillPopScope 并非监听返回按键,只是当前页面将要被pop时触发的回调
child: Container(),
onWillPop: () async{
return _doubleExitApp();
}
);
}
//双击返回 退出应用
bool _doubleExitApp(){
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
ToolUtils.ShowToast(msg: "再点一次退出应用");
//两次点击间隔超过1秒则从新计时
_lastPressedAt = DateTime.now();
return false;
}
//应用关闭直接取消 Toast
Fluttertoast.cancel();
return true;
}
///若是返回 return new Future.value(false); popped 就不会被处理
///若是返回 return new Future.value(true); popped 就会触发
///这里能够经过 showDialog 弹出肯定框,在返回时经过 Navigator.of(context).pop(true);决定是否退出
/// 单击提示退出
Future<bool> _dialogExitApp(BuildContext context) {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
content: new Text("是否退出"),
actions: <Widget>[
new FlatButton(onPressed: () => Navigator.of(context).pop(false), child: new Text("取消")),
new FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: new Text("肯定"))
],
));
}
}
复制代码