child: Text(
‘SHARE’,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Theme.of(context).primaryColor,
),
),
),
],
),
],
),
),
Container(
padding: const EdgeInsets.all(32.0),
child: Text(
'Lake Oeschinen lies at the foot of the Blüemlisalp in the ’
'Bernese Alps. Situated 1,578 meters above sea level, it ’
'is one of the larger Alpine Lakes. A gondola ride from ’
'Kandersteg, followed by a half-hour walk through pastures ’
'and pine forest, leads you to the lake, which warms to ’
'20 degrees Celsius in the summer. Activities enjoyed here ’
‘include rowing, and riding the summer toboggan run.’,
softWrap: true,
),
),
],
),
),
);
}
}
这只是一个静态组件树,没有实现任何行为。但是将视图逻辑直接嵌入到这样的树中估计不会是一次愉快的体验。
接受挑战。
重新审视代码编写 UI
使用 Flutter 的 UI-as-code 方法时,组件树就是代码。因此,我们可以使用所有常用的代码组织工具来改善这种情况。工具箱中最简单的工具之一就是命名子表达式。这会在语法上将组件树翻出来。而不是
return A(B(C(D(), E())), F());
我们可以命名每个子表达式并得到
final Widget d = D();
final Widget e = E();
final Widget c = C(d, e);
final Widget b = B©;
final Widget f = F();
return A(b, f);
我们的湖泊应用可以重写成下面这样:
import ‘package:flutter/material.dart’;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Widget imageSection = Image.asset(
‘images/lake.jpg’,
width: 600.0,
height: 240.0,
fit: BoxFit.cover,
);
final Widget titles = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
‘Oeschinen Lake Campground’,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Text(
‘Kandersteg, Switzerland’,
style: TextStyle(color: Colors.grey[500]),
),
],
);
final Widget stars = Row(
children: [
Icon(Icons.star, color: Colors.red[500]),
Text(‘41’),
],
);
final Widget titleSection = Container(
padding: const EdgeInsets.all(32.0),
child: Row(
children: [
Expanded(child: titles),
stars,
],
),
);
final Widget callAction = Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.call, color: Theme.of(context).primaryColor),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
‘CALL’,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Theme.of(context).primaryColor,
),
),
),
],
);
final Widget routeAction = Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.near_me, color: Theme.of(context).primaryColor),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
‘ROUTE’,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Theme.of(context).primaryColor,
),
),
),
],
);
final Widget shareAction = Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.share, color: Theme.of(context).primaryColor),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
‘SHARE’,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Theme.of(context).primaryColor,
),
),
),
],
);
final Widget actionSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
callAction,
routeAction,
shareAction,
],
),
);
final Widget textSection = Container(
padding: const EdgeInsets.all(32.0),
child: Text(
'Lake Oeschinen lies at the foot of the Blüemlisalp in the ’
'Bernese Alps. Situated 1,578 meters above sea level, it ’
'is one of the larger Alpine Lakes. A gondola ride from ’
'Kandersteg, followed by a half-hour walk through pastures ’
'and pine forest, leads you to the lake, which warms to ’
'20 degrees Celsius in the summer. Activities enjoyed here ’
‘include rowing, and riding the summer toboggan run.’,
softWrap: true,
),
);
final Widget scaffold = Scaffold(
appBar: AppBar(title: Text(‘Top Lakes’)),
body: ListView(
children: [
imageSection,
titleSection,
actionSection,
textSection,
],
),
);
return MaterialApp(
title: ‘Flutter Demo’,
home: scaffold,
);
}
}
缩进级别现在更合理,我们可以通过引入更多名称使子树的缩进级别变得像我们希望的那样浅。更好的是,通过为各个子树提供有意义的名称,我们可以表示每个子树的作用。所以我们现在可以谈谈 xxxAction
子树…并观察到我们在这里面有很多重复的代码!另一个基本的代码组织工具——功能抽象——负责这部分内容:
import ‘package:flutter/material.dart’;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Widget imageSection = …
final Widget titles = …
final Widget stars = …
final Widget titleSection = …
Widget action(String label, IconData icon) {
final Color color = Theme.of(context).primaryColor;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
label,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: color,
),
),
),
],
);
}
final Widget actionSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
action(‘CALL’, Icons.call),
action(‘ROUTE’, Icons.near_me),
action(‘SHARE’, Icons.share),
],
),
);
final Widget textSection = …
final Widget scaffold = …
return MaterialApp(
title: ‘Flutter Demo’,
home: scaffold,
);
}
}
我们将看到一个简单功能抽象的替代,它会更具有更 Flutter 风格的。
重新审视组成
接下来是什么?好吧,build
方法依然很长。也许我们可以提取一些有意义的作品…片断?组件!Flutter 的组件都是关于组合和重用的。我们用框架提供的简单组件组成了一个复杂的组件 但是发现结果过于复杂,我们可以选择把它分解成不太复杂的自定义组件。定制组件是 Flutter 世界中的一等公民,而明确定义的组件具有很大的潜力被重用。让我们将 action
函数转换为 Action
组件类型并将其放在自己的文件中:
import ‘package:flutter/material.dart’;
import ‘src/widgets.dart’;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Widget imageSection = …
final Widget titles = …
final Widget titleSection = …
final Widget actionSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Action(label: ‘CALL’, icon: Icons.call),
Action(label: ‘ROUTE’, icon: Icons.near_me),
Action(label: ‘SHARE’, icon: Icons.share),
],
),
);
final Widget textSection = …
final Widget scaffold = …
return MaterialApp(
title: ‘Flutter Demo’,
home: scaffold,
);
}
}
import ‘package:flutter/material.dart’;
class Action extends StatelessWidget {
Action({Key key, this.label, this.icon}) : super(key: key);
final String label;
final IconData icon;
@override
Widget build(BuildContext context) {
final Color color = Theme.of(context).primaryColor;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
label,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: color,
),
),
),
],
);
}
}
现在我们可以在应用程序的任何位置重用 Action
组件,就像它是由 Flutter 框架定义的一样。
但是,嘿,顶级的 action
功能不能满足同样的需求吗?
一般来说,不能。
- 许多组件是由其他组件构造的;它们的构造函数有
Widget
与List<Widget>
类型的child
和children
参数。所以action
函数不能传递给任何一个函数。当然,调用action
的结果可以。但是,你将通过在当前构建环境中预先构造的组件树,而不是StatelessWidget
,它只在必要时才构建子树,并且是最后在整个树中定义的上下文中定义的。注意到表达式中在Action.build
开头的Theme.of(context).primaryColor
了吗?它从父链上最近的Theme
组件中检索主颜色——在调用action
时,它很可能与最近的Theme
不同。 Action
is defined as aStatelessWidget
which is little more than a build function turned into an instance method. But there are other kinds of widget with more elaborate behavior. Clients ofAction
shouldn’t care what kind of widgetAction
is. As an example, if we wanted to endowAction
with an intrinsic animation, we might have to turn it into aStatefulWidget
to manage the animation state. The rest of the app should be unaffected by such a change.
重新审视响应式编程
状态管理是开始利用 Flutter 响应式编程模型,并让我们的静态视图生动起来的暗示。让我们定义应用程序的状态。我们将尽量保持简单,先假设一个 Lake
业务逻辑类,其唯一可变状态是用户是否已加星标:
abstract class Lake {
String get imageAsset;
String get name;
String get locationName;
String get description;
int get starCount;
bool get isStarred;
void toggleStarring();
void call();
void route();
void share();
}
然后,我们可以从 Lake
实例动态地构造我们的组件树,并且同时还可以设置事件处理程序以调用其方法。响应式编程模型的优点在于我们只需在代码库中执行一次。只要 Lake
实例发生变化,Flutter 框架就会重建我们的组件树——前提是我们告诉框架。这需要使 MyApp
成为一个 StatefulWidget
,这反过来又涉及将组件构建委托给一个相关的 State
对象,然后每当我们在 Lake
上加星标时调用 State.setState
方法。
import ‘package:flutter/material.dart’;
import ‘src/lake.dart’;
import ‘src/widgets.dart’;
void main() {
// 假装我们从业务逻辑中获取 Lake 实例。
final Lake lake = Lake();
runApp(MyApp(lake));
}
class MyApp extends StatefulWidget {
final Lake lake;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
都说三年是程序员的一个坎,能否晋升或者提高自己的核心竞争力,这几年就十分关键。
技术发展的这么快,从哪些方面开始学习,才能达到高级工程师水平,最后进阶到Android架构师/技术专家?我总结了这 5大块;
我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
《Android架构视频+BAT面试专题PDF+学习笔记》
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望**这份系统化的技术体系**对大家有一个方向参考。
面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
《Android架构视频+BAT面试专题PDF+学习笔记》
[外链图片转存中…(img-Em5B9wDG-1710674920432)]
[外链图片转存中…(img-92WtRdcE-1710674920432)]
[外链图片转存中…(img-MRn2MGcO-1710674920433)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望**这份系统化的技术体系**对大家有一个方向参考。
2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。