_[译]Flutter for Android Developers - Views

这有一个例子描述了怎样在屏幕上展示一个Widget,并且给他添加一些padding。

override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(“Sample App”),
),
body: new Center(
child: new MaterialButton(
onPressed: () {},
child: new Text(‘Hello’),
padding: new EdgeInsets.only(left: 10.0, right: 10.0),
),
),
);
}

这里看到其实在Flutter中是没有xml布局文件的存在了,取而代之的是直接在override的build方法中去布局,这其实有点类似RN,这里的build方法就类似RN中的render方法,只不过RN通过JSX使得render方法中通过xml语法来完成布局,而Flutter则是完全通过Dart语法来完成布局。可读性上我个人还是更喜欢Flutter,xml与js混写还是觉得有点别扭。 这里列出了Flutter提供的所有的布局。

小结: 在Flutter中不存在xml的布局形式,Widget的布局在build方法中直接构建。

怎么从布局中添加或者删除一个组件

  • in Android

  • 我们可以调用addChild或者removeChild方法去动态的添加或者删除一个ViewGroup中的View。

  • in Flutter

  • 因为widget是不可变的所以不能直接的addChild或者removeChild。但是可以传递一个返回Widget的方法给它的Parent,然后通过一个boolean值在该方法中控制要返回的Widget。

下面的代码展示了如何通过点击FloatingActionButton来触发在两个Widget之间切换:

import ‘package:flutter/material.dart’;

void main() {
runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: ‘Sample App’,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}

class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);

@override
_SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State {
// Default value for toggle
bool toggle = true;
void _toggle() {
setState(() {
toggle = !toggle;
});
}

_getToggleChild() {
if (toggle) {
return new Text(‘Toggle One’);
} else {
return new MaterialButton(onPressed: () {}, child: new Text(‘Toggle Two’));
}
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(“Sample App”),
),
body: new Center(
child: _getToggleChild(),
),
floatingActionButton: new FloatingActionButton(
onPressed: _toggle,
tooltip: ‘Update Text’,
child: new Icon(Icons.update),
),
);
}
}

代码也比较简单,关键在于_SampleAppPageState的build方法中Center的构造方法中的child参数传的是一个_getToggleChild方法。该方法通过一个toggle变量来决定返回给Center的是一个怎样的Widget。而toggle的赋值同样是由点击FloatingActionButton后调用setState来改变的。也就是说将toggle作为SampleAppPage的状态保存下来,在展示的时候由toggle的值来动态决定要展示的是什么Widget。

小结: 在Flutter中不能直接动态的去添加或者删除一个Widget到Widgets Tree中,因为Flutter中的Widget是不可变的。但我们可以依赖StatefulWidget根据State的不同来灵活的构建不同的Widget。

怎样对一个Widget做动画

  • in Android
  • 我们可以通过通过xml文件或者调用View.animate()方法创建一个动画。
  • in Flutter
  • 我们将需要做动画的Widget包裹到一个Transition中来实现。

像Android一样,在Flutter中我们也有AnimationController和Interpolator,Interpolator通过继承Animation类实现,比如下面例子中用到的CurvedAnimation。我们传递AnimationController和Animation到一个Widget中,然后通过AnimationController来启动动画。 下面的例子展示了使用FadeTransition来实现当按下按钮时将展示Logo的FlutterLogo Widget淡出的效果:

import ‘package:flutter/material.dart’;

void main() {
runApp(new FadeAppTest());
}

class FadeAppTest extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: ‘Fade Demo’,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyFadeTest(title: ‘Fade Demo’),
);
}
}

class MyFadeTest extends StatefulWidget {
MyFadeTest({Key key, this.title}) : super(key: key);
final String title;
@override
_MyFadeTest createState() => new _MyFadeTest();
}

class _MyFadeTest extends State with TickerProviderStateMixin {
AnimationController controller;
CurvedAnimation curve;

@override
void initState() {
controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Container(
child: new FadeTransition(
opacity: curve,
child: new FlutterLogo(
size: 100.0,
)))),
floatingActionButton: new FloatingActionButton(
tooltip: ‘Fade’,
child: new Icon(Icons.brush),
onPressed: () {
controller.forward();
},
),
);
}
}

整个Widget Tree还是跟之前类似,MaterialApp的构造函数中home参数传入的依然是我们自定义的一个继承自StatefulWidget的MyFadeTest,_MyFadeTest是其对应的State,其中定义了AnimationController和CurvedAnimation,AnimationController用于控制动画,CurvedAnimation是一个插值器实现。接着在build方法中通过将我们需要动画的FlutterLogo Widget包裹在一个FadeTransition中来让FlutterLogo Widget产生动画,最后在按下FloatingActionButton的回调中使用AnimationController.forward()方法来触发动画。 这里或者那里查看更多关于动画的具体细节。

小结: 在Flutter中也有AnimationController和插值器,通过AnimationController来控制动画的播放,插值器改变动画播放的加速度。 使用时先构造AnimationController,然后将构造好的AnimationController作为参数构造插值器,最后将构造好的插值器作为参数构造Transition。之后就可以通过AnimationController来控制Transition中包含的Widget的动画执行。

怎样使用Canvas去画内容

  • in Android
  • 我们可以用Canvas去画一些自定义的图形在屏幕上。
  • in Flutter
  • CustomPaint和CustomPainter这两个类可以帮助我们在Canvas上作画。

下面的代码实现一个可自由签名的Widget:

import ‘package:flutter/material.dart’;
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List points;
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
…color = Colors.black
…strokeCap = StrokeCap.round
…strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null)
canvas.drawLine(points[i], points[i + 1], paint);
}
}
bool shouldRepaint(SignaturePainter other) => other.points != points;
}
class Signature extends StatefulWidget {
SignatureState createState() => new SignatureState();
}
class SignatureState extends State {
List _points = [];
Widget build(BuildContext context) {
return new GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
_points = new List.from(_points)…add(localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),
child: new CustomPaint(painter: new SignaturePainter(_points)),
);
}
}
class DemoApp extends StatelessWidget {
Widget build(BuildContext context) => new Scaffold(body: new Signature());
}
void main() => runApp(new MaterialApp(home: new DemoApp()));

可以看到CustomPaint和CustomPainter搭配使用来实现了向Canvas上绘制自定义内容的目的。首先自定义SignaturePainter继承于CustomPainter,并重写paint方法,在本例中paint方法首先采用链式写法构造一个Paint实例paint,接着遍历points列表的内容来画线。points列表是构造SignaturePainter时传入的,里面保存了触摸屏幕的事件点的信息。其他部分其实与之前的结构都差不多。关键在SignatureState的build方法中返回的是一个GestureDetector,这是一个能够帮助我们捕获手势信息的Widget,在它的构造函数中child参数传入的是一个CustomPaint,CustomPaint的构造函数又传入了一个我们自定义的SignaturePainter,并且将手势捕获事件时捕获到的_points列表在这个时候传递给SignaturePainter。于是CustomPaint就和CustomPainter产生化学反应,相互配合完成在Canvas上作画的效果。

效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

小结: 在Flutter中实现在Canvas上作画需要CustomPaint和CustomPainter相互配合,首先继承CustomPainter自定义一个Painter并重写paint方法实现绘制逻辑。然后将自定义的CustomPainter传递给CustomPaint的构造方法,CustomPaint作为Widget Tree中的一个Widget使用自定义的CustomPainter完成绘制。

怎样构建自定义Widget

  • in Android
  • 自定义View一般通过继承View或者已经存在的其他组件并重写一些关键方法来实现。
  • in Flutter
  • 自定义一个Widget不是通过继承而是通过组合其他widgets。

让我们来看一个栗子:

class CustomButton extends StatelessWidget {
final String label;
CustomButton(this.label);

@override
Widget build(BuildContext context) {
return new RaisedButton(onPressed: () {}, child: new Text(label));
}
}

代码很简单,看到CustomButton一样还是继承于StatelessWidget。构造函数接受一个字符串参数并保存在内部成员变量label中。在build方法中返回的是一个RaisedButton(一个Flutter提供的Widget),巧妙的地方是在RaisedButton的构造函数中传入了一个Text(一个Flutter提供的Widget)作为其child参数。这个Text Widget显示的就是CustomButton的label成员中的内容。
在使用CustomButton的时候可以像使用其他Widget一样直接使用:
override
Widget build(BuildContext context) {
return new Center(
child: new CustomButton(“Hello”),
);
}
}
小结: 在Flutter中自定义Widget是通过组合不同的Widget来实现的,自定义的Widget只继承于StatelessWidget或者StatefulWidget,通过build方法中组合其他的Widget来实现自定义Widget。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
5792219246)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值