Flutter开发笔记(⼀)
最近在做项⽬,想集成 Flutter来开发部分组件。所以,开始了研究Flutter混合开发之路。欢迎加⼊ Dart 阵营。
跳过所有有关安装和运⾏ Flutter 应⽤程序的部分,直接进⾏操作,如果您不确定 Flutter 是什么,并且有许多问题,请阅读 关于 Flutter 的演进之路 。
Dart
如果你认为 Kotlin 是 Java 的替代,等到你看到 Dart 后,你会发现它是直截了当,没有样板代码的:
默认为public,通过前缀“_” 进⾏私有化;
集合; 点击试⽤
⼀切都是对象 - 没有“primitives”
命名参数,可选参数,默认值: 点击试⽤
属性 - ⽆需在任何地⽅写“get”⽅法
级联 - ⼀切都是构建者
使⽤ strong mode 类型推导 - 只需要在本地写“var”
命名构造函数,⾃动分配到字段; 点击试⽤
字符串插值,⼏种类型的字符串; 点击试⽤
dartfmt - 如果不想格式化 也可以不⽤这个⼯具
这⾥有⼀个 Dart 代码的例⼦,⼀个获取 IP 地址的私有⽅法:
_getIPAddress() async {
String url = '/ip';
var httpClient = createHttpClient();
var response = ad(url);
Map data = JSON.decode(response);
String ip = data['origin'];
}
设计模式
我很确定你已将你的 Android 技巧从⽆序代码扩展到 MVC、MVP、MVVM,Dagger2、DataBinding 和 Android 架构组件 ,Flutter 基本上就是⼀个 V(View),响应式视图,它可以是⽆状态或有状态的 widget,就连 AppCompatActivity 也是⼀个 widget。
让我们创建⼀个⾮常简单的 Activity,我们需要⼀个⽂本视图和⼀个更新该⽂本的按钮,下⾯是 Activity 代码(注意没有 XML):
public class Click extends Activity {
int count = 0;
protected void onCreate(Bundle bundle) {
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.button);
final TextView text = (TextView) findViewById(unter);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
count++;
text.setText("Button clicked " + counter + " times");
}
});
}
}
在 Flutter,你不需要操纵视图,就像 setText() 中的代码,你可以使⽤ state 来替代,并且 Flutter 将会处理好屏幕更新,在 Flutter 中和上述代码等价的是:
import 'package:flutter/material.dart';class Activity extends StatefulWidget {
@override
ActivityState createState() => new ActivityState();
}class ActivityState extends State<Activity> {
int counter = 0;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: ,
children: <Widget>[ new Text(
'Button clicked ${counter} times',
), new FlatButton(
child: new Text('Increment'),
onPressed: () {
setState(() {
counter++;
});
},
),
]
,
),
),flutter开发app
);
}
}
你也注意到,我们在 setState 中增加了 counter 的值,⼀旦 onPressed 被触发(之后是 setState),Flutter 将会使⽤新的 counter
值来重新渲染整个 widget 和 text 对象。
分离 widget 和 state(对于 Android 开发⼈员来说)的最⼤优点是,如果你在 Java 代码中旋转设备或调整窗⼝⼤⼩(⽀持多窗⼝),则计数器的值将被重置为零,你必须编写⼤量重复代码来管理 Activity 的⽣命周期。⽽在 Flutter 中,这是不需要的,现成的功能,⽆需额外的代码。
Async/Await
在 Android 开发中,UI 线程⾮常重要,完成速度稍慢的事情⼯作,会显⽰以下神秘⾏:
I/Choreographer(1378): Skipped 55 frames! The application may be doing too much work on its main thread.
这种情况你只能使⽤线程来处理,如下所⽰:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
// a potentially time consuming task
final Bitmap bitmap =
processBitMap("image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
上述代码可以很简单的使⽤ Dart 完成:
onClick() async {
Bitmap bitmap = await processBitMap("image.png");
// you don't want to update non-existent widget
if (!mounted) return;
setState(() {
imageView = bitmap;
});
}
这⾥发⽣了什么? async 修饰符标记的⽅法会安排稍后执⾏,该⽅法变成⾮阻塞的,因此你的应⽤程序不会丢失任何帧,await 修饰符挂起⽅法的执⾏,等待 processBitMap 完成,然后执⾏将会恢复。
Widget
⽬前有⼤量在 Android 之上运⾏的各种 OEM 软件和⽪肤,这都是可以理解的,因为每个制造商都希望为其设备建⽴⾃⼰的附加值,我不能计算我究竟说了多少次“Funck S*ms*ng”,OEM 定制对 Android 开发⼈员引⼊了很多难题.。
这种⽅法,⽆法保证你的应⽤程序在多种设备上看起来是⼀样的,尽管并不是所有的 Flutter widget 都经过优化,可以在平板电脑上也可以在较⼩屏幕的设备上正常⼯作。
⽆论如何,这种⽅法也为 UI 设计的创新打开了新的⼤门,例如,以下的代码可以使得⽤户改变 Activity 的⼤⼩:
class HeroScreen extends StatefulWidget {
@override
HeroState createState() => new HeroState();
}class HeroState extends State<HeroScreen> with SingleTickerProviderStateMixin {
bool _scaling = false;
Matrix4 _transformScale = new Matrix4.identity();
double scalePos = 1.0; set _scale(double value) =>
_transformScale = new Matrix4.identity()..scale(value, value, 1.0);
@override
Widget build(BuildContext context) { return new Scaffold(
body: new GestureDetector(
onScaleStart: (details) {
setState(() {
_scaling = true;
});
},
onScaleUpdate: (details) { var n = details.scale;
setState(() {
scalePos = n;
_scale = n;
});
},
onScaleEnd: (details) {
setState(() {
_scaling = false;
_scale = scalePos < 1 ? 1.0 : scalePos;
});
},
child: new Container(
color: Colors.black26,
child: new Transform(
transform: _transformScale,
child: new Center(
child: new Row(
mainAxisAlignment: ,
children: <Widget>[
new Text(_scaling ? "Scaling" : "Scale me up"),
]))))));
}
}
这让我们得到⼀个⾮常有趣的⼩部件,这样去写可重复使⽤的⼩部件就太容易了, 我可以将以上不太友好的代码转换成可重⽤且⼲净的⼩部件:
class Scale extends StatefulWidget { final Widget child; final GestureScaleStartCallback onStart; final GestureScaleEndCallback onEnd; final GestureSca
Scale({Key key, this.child, Start, Update, End})
: super();
@override
ScaleState createState() => new ScaleState();
}class ScaleState extends State<Scale> with SingleTickerProviderStateMixin {
Matrix4 _transformScale = new Matrix4.identity();
double scalePos = 1.0; set _scale(double value) =>
_transformScale = new Matrix4.identity()..scale(value, value, 1.0);
@override
Widget build(BuildContext context) { return new GestureDetector(
onScaleStart: Start,
onScaleUpdate: (details) {
setState(() {
scalePos = n;
_scale = n;
});
},
onScaleEnd: (details) {
setState(() {
_scale = scalePos < 1 ? 1.0 : scalePos;
});
},
child: new Container(
color: Colors.black26,
child: new Transform(
transform: _transformScale, child: widget.child)));
}
}
重构后的代码如下:
class HeroScreen extends StatefulWidget {
@override
HeroState createState() => new HeroState();
}class HeroState extends State<HeroScreen> with SingleTickerProviderStateMixin {
bool _scaling = false;
@override
Widget build(BuildContext context) { return new Scaffold(
body: new Scale(
onStart: (details) => setState(() => _scaling = true),
onUpdate: (details) {},
onEnd: (details) => setState(() => _scaling = false),
child: new Container(
color: Colors.black26,
child: new Center(
child: new Row(
mainAxisAlignment: ,
children: <Widget>[ new Text(_scaling ? "Scaling" : "Scale me up"),
]))),
));
}
}
其他
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论