Android控件 vs Flutter控件
一. 开始
在Android中View是所有控件的基础, 在Flutter中与View对等的是Widget. 但Widget又不同于Android中的views. 在Flutter中你可以声明构造界面.
Flutter中的控件不能修改, 一直到它们需要改变. 当状态发生变更, Flutter的底层会重新创建一颗新的控件树实例. 而在Android中控件绘制一次就不再绘制, 直到invalidate
被调用.
由于不可变性, Flutter的控件很轻量. 因为它们不是视图本身,也不是直接绘制任何东西,而是对UI及其语义的描述. 最终才会被构造成实际的试图对象.
二. Android控件
常用基础控件View, TextView, Button, ImageView, 其它控件如ProgressBar, SeekBar等.
这些控件都继承自View. 基础控件不够用时, 可继承这些控件实现自己想要的特性.
在android中存在5种基本布局
- 线性布局(LinearLayout)
- 相对布局(RelativeLayout)
- 表格布局(TableLayout)
- 帧布局(FrameLayout)
- 绝对布局(AbsoluteLayout)
TableLayout和AbsoluteLayout我基本没有用到. LinearLayout用于布局水平一行或者纵向一行.
FrameLayout用于布局有层次的界面, 可以简单设置居中. 更复杂控件间的相对关系使用RelativeLayout布局.
FrameLayout性能会好于RelativeLayout, 当FrameLayout无法解决的时候才用RelativeLayout
RelativeLayout通过相对关系也能布局出LinearLayout的界面, 但不如LinearLayout直观
列表可滑动滑动布局ScrollView/ListView/GridView/RecyclerView/ViewPager.
上述控件继承自ViewGroup, ViewGroup又继承于View 相对于继承View的控件, 前者内部可包含子控件, 而后者不行.前者一般会实现onLayout和onMeasure, 来控件子控件的布局和大小. 这些布局不够用时, 也可继承这些控件实现自己想要的特性.
上述所有控件都有的属性有
- 宽度(layout_width)
- 高度(layout_height)
- 背景(backgroud)
- 内间距(padding)
- 外间距(margin)
- 可见性(visibility)
- 位于父控件的位置(layout_gravity)
- 内部子控件的位置(gravity, 继承自ViewGroup的才有)
- 点击事件(onClick)
- 动画属性(alpha/rotation/scale)
三. Flutter控件
flutter中的控件非常多, 每一种布局只具备特定的特性. 功能划分的非常细. 最大的不同也正是这点, 基本控件不再拥有通用属性,比如背景, 点击事件等, 这些都被独立出来成为单独的控件.
举个简单例子如下
Android例子
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:onClick="xxx"
android:gravity="center"
android:text="按钮"
android:textSize="18sp"
android:textColor="0xffffffff"
android:layout_width="100dp"
android:layout_height="40dp"
android:background="0xff808080"/>
</LinearLayout>
Flutter例子
var layout = Column(
children: <Widget>[
GestureDetector(
child: Container(
width: 100.0,
height: 40.0,
color: Color(0xff808080),
child: Center (
child: Text(
'按钮',
style: TextStyle(
color: Color(0xffffffff),
fontSize: 18.0,
),
),
)
),
onTap: () {
print('clicked');
},
),
],
);
可以看出在Flutter中, 属性都被提取成一个控件了, GestureDetector负责处理点击事件, Container负责大小和背景, Center负责居中.Text仅仅只有文字相关的属性, 这样Android一个简单的控件在Flutter中需要嵌套很多层才能实现. 但好处就是划分的很细, 可以任意组合.
基本的显示控件有Text, Image, Icon, RaisedButton等.属性功能控件有Container, Padding, Center, Align, FittedBox等.这些都是Single-child控件. 就是child属性指向为Widget.
布局控件有Row, Column, Stack, IndexedStack, GridView, ListView等.这些都是Multi-child控件. 就是child属性指向为<Widget>[].
四. 实现自定义控件
在Android中通常是继承View或其它基于View的控件. 然后重写其中的方法, 来获取想要的行为.
在Flutter中, 你只需要组合各种小组件而不是继承. 某种程度上类似于实现Android中的一个自定义ViewGroup. 各种组件单元都已经存在, 你只是提供一种不同的行为, 比如, 重新定义布局逻辑.
举个例子: 你想实现一个在构造时获取文字的CustomButton
. 你可以通过RaisedButton
组合文字, 而不是继承RaisedButton
.
class CustomButton extends StatelessWidget {
final String label;
CustomButton(this.label);
@override
Widget build(BuildContext context) {
return RaisedButton(onPressed: () {}, child: Text(label));
}
}
然后使用CustomButton
就像跟其它Flutter组件一样:
@override
Widget build(BuildContext context) {
return Center(
child: CustomButton("Hello"),
);
}
五. Android/Flutter映射表
Android | Flutter |
---|---|
TextView | Text |
ImageView | Image |
Button | RaisedButton |
LinearLayout | Row/Column |
FrameLayout/RelativeLayout | Stack |
ListView | ListView |
GridView | GridView |
ViewPager | PageView |