Flutter - Weight 入门
从 C 开始,我们进步到 java,再到 kotlin,现在又迎来了 Dart、Flutter,还要去学学 python。时代在进步,我们也得跟着进步,新的思想、新的工具、新的语言,速度越来越快,东西越来越多,不停学习真是 coder 这行不变的准则啊
阅读完本文推荐大家唉再去看看这篇,毕竟孤木难支,取长补短嘛~,下面这篇也是极好的:
Flutter 没有 Activity 概念
稍稍了解 Flutter 的同学都应该知道 Flutter 构建的 android 项目整个 app 只剩下 MainActivity 这一个 Activity 了,其内部使用一个 FlutterView 来承载所有的Flutter 页面
,看下图:
所以 Flutter 天然的就没有页面这个概念了,Flutter 遵循 RN、前端的页面搭建思路,在 UI 这块和 android 有天壤之别,android 那种独特的写 xml 布局的方式从此是路人,历史又回归了主流
先尝个味,不要以为 Flutter 跑在 android 上就还是 android 那套,Flutter 绝逼是另一个全新的东西了。不是之前想的简简单单学学就能搞定的了,是要狠下心来耗费一番功夫的。这里我们先从 Flutter 页面搭建开始一步步深入理解 Flutter 的魅力,或者说熟悉下主流前端开发
吐槽 Flutter 的 Weight
就像 JAVA 那样一切皆对象
有个口号,Flutter 也有自己的口号:一切皆 Weight
,怎么理解呢,直接去看 Flutter 社区的朋友中绝对有这种表情的:
官方中文文档绝逼退治
效果一流,至少我这样的就有些懵逼
的感觉,其实这是大家思路停留在 android 的问题,抱着 android 的期待来学习 Flutter 绝对懵逼。要是我们当做新的语言来学习的话,静下新来仔细找找规律、思路的话反到是学起来轻松很多
android 里
- -> 我们把 textview 写在 ConstraintLayout、LinearLayout、RelativeLayout 这样的
布局容器
里,然后在自己的 xml 标签里写自身的属性,宽高,位置,样式,什么样的属性都可以写,甚至还能自定义自己想要的属性进来
<android.support.constraint.ConstraintLayout
<Button
android:id="@+id/btn_toast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="toast 组件"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
- -> 然后我们用一个专门的 xml 文件来承载 UI 样式
- -> 再然后一个 Activity 会解析处理渲染这个 xml 文件
- -> android app 使用专门的
栈
来管理这些 Activity 的进进出出
android 的 UI 层,命名规范:布局容器
都用layout
结尾、内容部件
都用view
结尾、属性设置位置统一
Flutter 里
一切都变了:
- Weight 不再清晰了,是像怎么叫就怎么叫
- Weight 责任更多了,很多 Weight 组件肩负很多任务,有些相同的任务又有好几个 Weight 可供选择
- 属性设置不再统一了,有了层级之分
当我看完 Flutter 的 Weight 之后,心里是哇凉哇凉的啊...
android 的经验一点用都没了,宝宝心里苦啊...
Flutter weight 特性
在学习 Flutter weight 之前一定要了解 Flutter weight 特性...
1. Flutter 是声明式编程
这点是和 android 有决定性差别的,Android 我们是写 xml 文件,activity 里面拿到 view 的引用,Flutter 不是的,Flutter 直接 A 代码画 UI,没了那烦人的 xml 文件。优点是:书写简便,代码少,随意性强,像怎么写怎么写。缺点是:没有预览,时间长了再看很麻烦,需要借助第三方工具查看UI 结构
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
wordPair.asPascalCase,
),
RandomWord(),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
RaisedButton(
onPressed: _other,
child: Text("减一"),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
2. Flutter weight 天然实现了数据绑定
其实这个特性也是声明式编程
的一部分,拿出来说效果好一些。在 android 里面我们只能拿到 view 引用 setXXXValue 才能修改该 view 的值,想要实现响应式 UI(UI 和数据绑定)还需要接触其他组件,还要学一些额外的代码
Flutter 就没这么麻烦,Weight UI 直接就是和数据是绑定的,只要在 setValue({...}) 里面修改值就能更新 UI,看下面的例子(删除了无关代码):
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _other() {
setState(() {
_counter--;
});
}
@override
Widget build(BuildContext context) {
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
RaisedButton(
onPressed: _other,
child: Text("减一"),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
一个 text 用来显示文本(count 的值),RaisedButton 按钮点一下 -1,floatingActionButton 点一下 +1,onPressed 属性配置点击方法,只要 text 组件里面引用了 count 的值就行,然后我们只要使用系统 API setState 修改值就 OK 啦
setState(() {
_counter--;
});
Flutter 放弃 xml 结合 UI 响应式编程的思路比传统 android 方便多了,android 计就算是上了 DataBinding 在 xml 里写 UI 赋值逻辑,那也远远没 Flutter 直观啊,Flutter 又不是打开其他文件,直接就看了,多省事...程序员都是懒人,只要能偷懒,就是进步,就是优秀的
3. Flutter 对属性的拆分
这里 Flutter 是学习前端的,android 里我们可以在 xml 下对 view 配置任何属性,按照分类可以分成:宽高大小类的
、位置定位类的
、各种边距,边框,背景
、view 自身的属性
Flutter 把除了view 自身的属性
之外的其他属性逗提升为 layout 容器级别,比如说你在 Flutter 里给一个 text 添加 padding,那么就得在这个 text 外面套上这么一层 padding 的容器
Padding(
padding: EdgeInsets.all(10),
child: (Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
)),
),
就是这个样子,属性提升成了容器了,Flutter 的容器绝对了里面 view 的外观(外在属性),具体的绘制则交给了该容器内部的 weight,这看着感觉好像模板设计模式啊,外面是模板,里面是可变部分
OK,有这些打底,下面 Flutter 的 weight 就好理解了
Flutter Weight 层级划分
在 Flutter 里一切揭 Weight,Weight 像 view 一样在 Flutter 也是所有 view 的父类
Weight 按照功能划分,可以这么看:
- 负责具体绘制的
内容 Weight
- 负责组织 Weight 样式
布局 Weight
,内部可以有多个子 Weight - 负责外在样式的
修饰 Weight
,内部只能有1个子 Weight
结合 android 来看的话:
-
内容 Weight
= textview 这样的 view -
布局 Weight
= LinearLayout、RelativeLayout 这样的布局容器 -
修饰 Weight
= width、height、padding 这些属性
布局 Weight
Flutter 的 布局 Weight
比较典型的有:row、Column。row 是一行,Column 是一列
- row 一行
class oneRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("AAAAAA"),
Text("BBBBBB"),
Text("CCCCCC"),
],
);
}
}
- Column 一列
class oneColume extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("AAAAAA"),
Text("BBBBBB"),
Text("CCCCCC"),
],
);
}
}
修饰 Weight
修饰 Weight
最经典的就是 Container 了,这里我们设置一个背景色
class oneContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
color: Colors.lightBlueAccent,
child: oneRow(),
);
}
}
具体的 weight 这里就不写了,那是下一节的学习内容,通过这几个小例子让大家熟悉下 Flutter 的 Weight 结构,后面就好学多了,就算是去官方文档也会顺利很多
Flutter 如何组织页面
Flutter 虽然没有 Activity 这样的页面
概念,但是 UI 出图可都是一个页面一个页面的,既然设计环节依然存在页面
,那么 Flutter 也必须有页面
或者相近的概念才能让我们的 UI设计图落地啊
在 Flutter 中和页面
概念最接近的就是 Flutter 中唯二名字里带 Weight 的组件了:StatelessWidget
和 StatefulWidget
Flutter 所有的 UI、页面都是在一个 FlutterView 上显示的,大家把StatelessWidget
和 StatefulWidget
理解为 ViewTree + viewGroup,或者直接理解成 layout 就 OK了
好比 android xml 里一层套一层的 layout,大 layout 里套小的 layout,上面 Container 的例子里,oneContainer 里面不就是套了一个 row 嘛,上面例子里我们把 layout 写成一个 class,这就是 Flutter 的自定义 viewGroup 了,大家看着简单不,省代码不
StatelessWidget
和 StatefulWidget
的区别就是能不能在自己 layout 内部修改自己的 UI,能该的就是 StatefulWidget
,不能该的必须依赖父层级修改 UI的就是 StatelessWidget
在代码上的区别就是之前提到过的 setValue 修改 UI了,StatefulWidget 里可以跑 setValue 方法,setValue 方法实际就是多次调用了 StatefulWidget 的 build 方法,StatelessWidget
反之
然后 Flutter 有专门切换 StatelessWidget
和 StatefulWidget
显示不同页面的 API,后面讲
最后
本文其实并不是直接去学习如何使用 Flutter Weight,而是尝试梳理下 Flutter 中 Weight 的分类,相互关系,提供给看了 Flutter 有些懵或者还没有开始 Flutter 学习的朋友一些便利,希望能带给大家帮助