_[译]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。

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
14969592050)]

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

[外链图片转存中…(img-bZ4kyvT4-1714969592052)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值