1.Flutter 中的 View
在 Flutter 中,可以将 Widget 当做 Android 中的 View,但并不是完全等价。Widget 的生命周期是不可变的,每当 Widget 或其状态发生变化时,Flutter 的框架都会创建一个新的实例树。
Flutter 包含了 Material 组件库,这些 widgets 遵循了 Material 设计规范。
2.更新Widgets
在 Flutter 中,Widgets 是不可变的,不会直接更新,相反,可以通过 Widget 的状态更新它们。
StatelessWidgets 适用与当我们秒速的用户界面不依赖于对象中的配置信息时,如 app 的 logo。
如果根据网络或用户交互更新 UI,必须使用 StatefulWidget 告诉 Flutter 框架 Widget 的状态已更新,以便更新改 Widget。
如果 Widget 在 build 之外更新(如用户交互),则它是有状态的。如果 Widget 永远不会改变,一旦创建它就是无状态的。但是,如果它是有状态的,包含它的父窗口小部件本身不对这些更新做出反应,父 Widget 仍然可以是无状态的。
使用 StatelessWidget ,Text就是一个常见的 StatelessWidget :
new Text(
'Hello';
style: new TextStyle(fontWeight: fontWeight.bold),
);
如果想让上面文字通过点击按钮发生变化,需要用 StatefulWidget :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '123',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String textShow = "Hello";
void _updateText() {
setState(() {
textShow = "Flutter";
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyApp"),
),
body: Center(
child: Text(textShow)
),
floatingActionButton: FloatingActionButton(
onPressed: _updateText,
tooltip: '更新了文字',
child: const Icon(Icons.update),
),
);
}
}
3.更新布局
在 Flutter 中,通过写一个 widget 树来声明布局。
实现一个带有 padding 的简单 widget:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyApp"),
),
body: Center(
child: MaterialButton(
onPressed: (){},
child: Text('Hello'),
padding: EdgeInsets.only(left: 10.0,right: 10.0),
)
),
);
}
4.布局中添加或删除组件
在 Flutter 中,Widget 是不可变的,所以没有类似的方法,相反,可以传入一个函数或表达式,该函数或表达式返回一个 Widget 给父项,并且通过布尔值控制改 Widget 的创建。
点击一个 FloatingActionButton,在两个 widget 质检切换:
class _MyHomePageState extends State<MyHomePage> {
bool tog = true;
void _tog() {
setState(() {
tog = !tog;
});
}
_getTogChild() {
if (tog) {
return Text("Hello");
} else {
return MaterialButton(onPressed: () {}, child: Text("你好"));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyApp"),
),
body: Center(
child: _getTogChild(),
),
floatingActionButton: FloatingActionButton(
onPressed: _tog,
tooltip: '更新文字',
child: Icon(Icons.update),
),
);
}
}
5.对 Widget 做动画
在 Flutter 中,使用动画库包裹 widgets,而不是创建一个动画 widget。
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
late AnimationController controller;
late CurvedAnimation curve;
@override
void initState() {
// TODO: implement initState
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("123"),
),
body: Center(
child: Container(
child: FadeTransition(
opacity: curve,
child: FlutterLogo(
size: 100.0,
)))),
floatingActionButton: FloatingActionButton(
tooltip: 'Fade',
child: Icon(Icons.brush),
onPressed: () {
controller.forward();
},
),
);
}
}
6.绘图(Canvas draw/paint)
Flutter 绘制类似于 Android,用到 Canvas API。Flutter可以借助两个类来帮助绘制:CustomPaint和 CustomPaninter 。
下面展示如何用 CustomPaint widget 在绘制阶段绘制。它实现了抽象类 CustomPainter,并将其传递给 CustomPaint 的 painter 属性。CustomPaint 子类必须实现 paint 和 shouldRepaint 方法;
绘制一个圆形和一个长方形:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: 'Flutter bottomNavigationBar',
theme: new ThemeData.fallback(),
home: _MyCanvas(),
);
}
}
class MyCanvasPainter extends CustomPainter{
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
Paint paint = Paint();
paint.color = Colors.amber;
canvas.drawCircle(Offset(100.0,200.0), 40.0, paint);
Paint paintRect = Paint();
paintRect.color = Colors.lightBlue;
Rect rect = Rect.fromPoints(Offset(150.0,300.0), Offset(300.0,400.0));
canvas.drawRect(rect, paintRect);
}
@override
bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
@override
bool shouldRebuildSemantics(MyCanvasPainter oldDelegate) => false;
}
class _MyCanvas extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: CustomPaint(
painter: MyCanvasPainter(),
),
);
}
}
7.自定义 Widgets
在 Android 中,可以通过继承 View 或已存在的某个控件,覆盖里面绘制方法实现自定义 View;
在 Flutter 中,推荐组合多个小的 widgets 来构建一个自定义的 widget。
如果想自定义一个 Button,需要组合 RaisedButton 和 label。
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Center(
child: new CustomButton("你好"),
);
}
}
class CustomButton extends StatelessWidget{
final String label;
CustomButton(this.label);
@override
Widget build(BuildContext context) {
// TODO: implement build
return new RaisedButton(onPressed: (){},child: new Text(label));
}
}
8.设置 Widget 的透明度
在 Flutter 中想改变透明度,可以给 widget 包裹一个 Opacity widget 来做到:
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter学习',
home: Scaffold(
appBar: AppBar(
title: Text('一起学习'),
),
body: Opacity(
opacity: 0.1,
child: new Center(
child: Text('HelloWorld'),
),
)),
);
}
}