Flutter widget 的设计思想跟 Android 略有不同,Flutter 中的 widget 可以用两条规则来约束:
- 一切都是 widget
- 每个 widget 只负责自己关注的部分
第一条意味着你所看到的东西都是由于 widget 构成,跟安卓不同的是,原本在安卓中一些参数相关的东西到了 Futter 中都被 widget 化,例如大小、背景、margin、padding 等等原本只需要一个参数设置的东西对应到 Flutter 中都映射成了 widget。
第二条的意思是,每个 widget 应该仅负责自己的职责所在,比如文本框 Text 组件,只负责如何显示一个文本,其他一概不管,不用考虑自己的大小、位置、margin 等等,这些由别的专门负责此功能的 widget 来控制。作为一个文本框就应该有文本框的觉悟。
举个栗子,我们希望显示一个文本时一个 Text 控件既可,但如果想控制它的大小、边距、位置这些属性就需要外面包一个 Container 来控制了。
关于如何安装 Flutter、创建项目等可以参照我的上一篇文章:
https://www.jianshu.com/p/a54090544662
两种 Widget
Widget 总体上分为两种:StatelessWidget 和 StatefulWidget。
StatelessWidget 表示不可变的 widget,例如一些固定的标题、Icon 等等,widget 的特征不会在运行时发生变化。
StatefulWidget 相反,其属性可能会在运行时发生变化,例如进度条、输入框等等。
在使用上,StatelessWidget 会通过 build 方法创建一个不可变的 widget,这样 widget 只需要绘制一次。
我们在使用时直接继承它然后实现 build 方法既可。
class StatelessText extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Text("Stateless");
}
}
而 StatefulWidget 中需要包含一个 State 对象来表现不同的状态,首先使用 createState 方法创建一个 State 对象,再通过 State 中的 build 方法创建一个 widget,后面每次状态变化时都会调用 build 方法重新绘制一个 widget。我们可以使用 setState 方法来触发 widget 更新。
这种使用起来也稍微麻烦点:
class EnableButton extends StatefulWidget {
final bool enable;
EnableButton(this.enable);
@override
State<StatefulWidget> createState() {
return ButtonState(enable);//返回一个 State 对象
}
}
class ButtonState extends State<EnableButton> {
bool enable;
ButtonState(this.enable);
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
setState(() {
enable = !enable;
});
},
child: Text(enable ? "Enable" : "Disable",
style: TextStyle(color: enable ? Colors.red : Colors.grey)));
}
}
主要代码都在 ButtonState 中,我们需要在它里面通过不同的状态来返回不同的 Widget。
常用 Widget
下面介绍几种常用的 widget。
Text(文本框)
文本框是最常见的 widget,简单得很。
Text text = Text("TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText",
textAlign: TextAlign.start,
textDirection: TextDirection.ltr,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.black));
常用参数:
- textDirection:设置文本居中模式
- textDirection:设置文本方向,默认为 ltr,对于一些习惯于从右至左阅读的国家来说可以设置为 rtl
- maxLines:最大行数
- overflow:超出文本如何处理,ellipsis 为超出部分使用 ... 显示
Image(图片)
Image 用于展示一张图片,图片源可以是文件、资源、内存及网络。通过不同的方法加载不同的图片源:
Image.network(url);
Image.asset(path);
Image.file(file);
Image.memory(bytes);
Image image = Image.asset("assets/valley.jpg",
width: 250,
height: 250,
fit: BoxFit.contain);
width 和 height 是宽高,fit 是填充模式,填充模式分为如下几种类型:
-
contain:在不缩放的情况下保证至少有一个方向充满且图片完全能显示出来
-
cover:在不缩放的情况下保证至少一个方向上充满但不保证图片完全显示
-
fill:不考虑宽高比,只保证图片完全填满
-
fitHeight:保证高度填满,即使宽度溢出
-
fitWidth:保证宽度填满,即使高度溢出
-
none:不应用任何设置,按照图片原有尺寸居中
-
scaleDown:等同 none,但如果尺寸超出则缩放填满
Button(按钮)
Flutter 中有两种按钮:FlatButton 和 RaisedButton,除了 RaisedButton 多了个背景色外其它的都一样。我们看一下怎么使用:
FlatButton flatButton = FlatButton(
onPressed: () => debugPrint("FlatButton Clicked"),
child: Text("FlatButton"));
RaisedButton raisedButton = RaisedButton(
onPressed: () => debugPrint("RaisedButton Clicked"),
elevation: 10,
color: Colors.yellow,
textColor: Colors.black87,
disabledColor: Colors.blue,
focusColor: Colors.red,
hoverColor: Colors.red,
highlightColor: Colors.blue,
splashColor: Colors.red,
child: Text("RaisedButton Clicked"));
主要参数:
- onPressed:点击事件
- elevation:阴影高度
- color:背景色
- textColor:文本颜色
- disabledColor:不可点击时的背景色
- focusColor:按钮获取输入焦点时的颜色
- hoverColor:鼠标悬停在按钮上时的颜色
- highlightColor:按下的颜色
- splashColor:点击时波纹颜色
- child:按钮内容
除了上面的之外还有很多参数,这里就不详细介绍了。
需要注意的是,child 可以设置为 任意 widget,例如一张图片。
TextField(输入框)
TextField 也是个常用的控件,内置了丰富的参数。
@override
Widget build(BuildContext context) {
ScrollController scrollController = new ScrollController();
TextEditingController textEditingController = TextEditingController();
TextField textField = TextField(
controller: textEditingController,
textAlign: TextAlign.start,
minLines: 1,
maxLines: 1,
maxLength: 5,
obscureText: true,
autofocus: true,
scrollController: scrollController,
cursorColor: Colors.red,
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.blue),
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly,
BlacklistingTextInputFormatter.singleLineFormatter
],
);
return Container(
child: Column(
children: <Widget>[
textField,
RaisedButton(
onPressed: () => {debugPrint(textEditingController.text)},
child: Text("Click"),
)
],
),
);
}
常用参数:
- controller:输入控制器
- textAlign:对齐方式
- minLines:最小行数
- maxLines:最大行数
- maxLength:最多可输入个数
- obscureText:输入密码
- autofocus:自动获取焦点
- scrollController:滚动控制器
- cursorColor:光标颜色
- style:文本样式
- inputFormatters:输入格式化,上述代码表示只允许输入数字及限制为单行
最后通过 textEditingController.text 即可获取输入的文本。
下面再介绍几个布局控件。
Container
这是个简单的布局控件,提供了大小、位置、背景等功能。
Container container = Container(
width: 200,
height: 100,
padding: EdgeInsets.all(10.0),
margin: EdgeInsets.only(top: 5.0, bottom: 5.0),
decoration: BoxDecoration(color: Colors.blue,
borderRadius: BorderRadius.circular(10.0)),
child: Text("Text"),
);
主要参数:
- width/height:宽高值
- padding:内间距
- margin:边距
- decoration:可以设置一些可绘制的东西,例如圆角,背景色等等
- child:子控件,也就是 Container 包装的控件
与 Container 对应的几个简单的布局还有 Padding,Center 等等。
Row/Column 及 Expanded
Row 和 Column 是线性布局,Row 表示水平布局,Column 表示垂直布局,控件将会按照一个方向上依次排序,类似于 Android 中的 LinearLayout。
var row = Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[Text("Text")],
);
常用参数:
- mainAxisSize:row 的宽度,max 表示尽可能的最大(一般等于屏幕宽度),min 表示尽可能小
- mainAxisAlignment:水平方向上的对齐方式
- crossAxisAlignment:竖直方向上的对齐方式,Row 的高度为最高子控件的高度
Column 与 Row 的参数一样,只不过控制的方向相反。
Expanded 表示将沾满改行所有剩余可用空间,如果该行有多个 Expanded,可以使用 flex 参数控制占用比例。
var row = Row(
children: <Widget>[
Expanded(flex: 1, child: Text("Text")),
Expanded(flex: 2, child: Text("Text")),
Text("Text"),
],
);
如上代码所示,两个 Expanded 将占用除了最后一个 Text 之外的所有空间,且两个 Expanded 宽度比例为 1:2。
Stack
Stack 布局支持控件堆叠,一个控件可以放在另一个控件的上面,也可以通过一些参数来调整控件的位置。
Stack stack = Stack(
alignment: AlignmentDirectional.topCenter,
children: <Widget>[
Container(
width: 300,
height: 300,
color: Colors.blue,
),
Positioned(left: 50, top: 50, child: Text("Text")),
Text("Text"),
],
);
Stack 大小同样等于最大控件的大小,所以上面代码中的 Stack 大小等于子控件 Container 大小。
常用参数:
- alignment:子控件的对齐方式,除了 AlignmentDirectional 中内置的几种对其方式外我们还可以自己定义。规则是,Stack 中心点表示为 [0, 0],左上角 [-1, -1],右下角 [1, 1],所以 alignment 中参数的取值范围为 -1 到 1。举个栗子:假设 Stack 大小为 200 * 200,当我们设置 alignment 为 Alignment(-0.7, 0.3) 时表示,子控件的 x 坐标为 30,y 坐标也为 170.
我们还可以结合使用 Positioned 来控制子控件的位置,Positioned 中提供了 left/top/right/bottom 四个参数来控制子控件的位置。
网友评论