当前位置:   article > 正文

Flutter学习指南:UI布局和控件,三面蚂蚁核心金融部

Flutter学习指南:UI布局和控件,三面蚂蚁核心金融部

这里看起来可能有些绕,BarWidget 依赖了 _BarWidgetState,而 _BarWidgetState 又继承了 State< BarWidget>。如果读者不太理解,其实也没有什么关系,这只是一个样板代码,照着写就行了。

从 BarWidget 的实现来看,好像跟前面使用 StatelessWidget 没有什么区别,都是在 build 方法里面返回一个 Widget,只是 stateful widget 把这个方法挪到了 State 里面。实际上,两者的区别非常大。stateless widget 整个生命周期里都不会改变,所以 build 方法只会执行一次。而 stateful widget 只要状态改变,就会调用 build 方法重新创建 UI。

为了触发 UI 的重建,我们可以调用 setState 方法。下面的代码读者留意一下即可,在后面我们学习了相关的控件后再回过头来看。

class BarWidget extends StatefulWidget {
@override
State createState() {
return _BarWidgetState();
}
}

class _BarWidgetState extends State {
var i = 0;

@override
Widget build(BuildContext context) {
return Row(
children: [
Text(‘i = $i’),
RaisedButton(
onPressed: () {
setState(() {
++i;
});
},
child: Text(‘click’),
)
],
);
}
}

下面我们开始学习一些具体的控件。

文本

为了展示文本,我们使用 Text:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(“Put your text here”);
}
}

这就是最简单的文本了,它使用的是默认的样式。很多情况下,我们都需要对文本的样式进行修改,这个时候,可以使用 TextStyle:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
“Put your text here”,
style: TextStyle(
color: Colors.blue,
fontSize: 16.0,
fontWeight: FontWeight.bold
),
);
}
}

图片

使用 Image,可以让我们向用户展示一张图片。图片的来源可以是网络、文件、资源和内存,它们对应的构造函数分别是:

Image.asset(name);
Image.file(file);
Image.memory(bytes);
Image.network(src);

比方说,为了展示一张来自网络的图片,我们可以这样:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image.network(
“http://www.example.com/xxx.png”,
width: 200.0,
height: 150.0,
);
}
}

按钮

Flutter 提供了两个基本的按钮控件:FlatButton 和 RaisedButton,它们的使用方法是类似的:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
var flatBtn = FlatButton(
onPressed: () => print(‘FlatButton pressed’),
child: Text(‘BUTTON’),
);
var raisedButton = RaisedButton(
onPressed: () => print(‘RaisedButton pressed’),
child: Text(‘BUTTON’),
);
return raisedButton;
}
}

通过设置 onPressed 回调,我们可以在按钮被点击的时候得到回调。child 参数用于设置按钮的内容。虽然我们给 child 传递的是 Text,但这不是必需的,它可以接受任意的 Widget,比方说,Image。

注意,由于我们只是在按钮点击的时候打印一个字符串,这里使用 StatelessWidget 是没有问题的。但如果有其他 UI 动作(比如弹出一个 dialog,则必须使用 StatefulWidget)。

它们的区别只是样式不同而已的:

FlatButton:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

flat-button

RaiseButton:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

raised-button

文本输入框

Flutter 的文本输入框叫 TextField。为了获取用户输入的文本,我们需要给他设置一个 controller。通过这个 controller,就可以拿到文本框里的内容:

class MessageForm extends StatefulWidget {
@override
State createState() {
return _MessageFormState();
}
}

class _MessageFormState extends State {
var editController = TextEditingController();

@override
Widget build(BuildContext context) {
// Row、Expand 都是用于布局的控件,这里可以先忽略它们
return Row(
children: [
Expanded(
child: TextField(
controller: editController,
),
),
RaisedButton(
child: Text(“click”),
onPressed: () => print(‘text inputted: ${editController.text}’),
)
],
);
}

@override
void dispose() {
super.dispose();
// 手动调用 controller 的 dispose 方法以释放资源
editController.dispose();
}
}

显示弹框

在前面的 TextField 例子中,我们只是把用户的输入通过 print 打印出来,这未免也太无趣了。在这一小节,我们要把它显示在 dialog 里。为了弹出一个 dialog,我们需要调用 showDialog 方法并传递一个 builder:

class _MessageFormState extends State {
var editController = TextEditingController();

@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: TextField(
controller: editController,
),
),
RaisedButton(
child: Text(“click”),
onPressed: () {
showDialog(
// 第一个 context 是参数名,第二个 context 是 State 的成员变量
context: context,
builder: (_) {
return AlertDialog(
// dialog 的内容
content: Text(editController.text),
// actions 设置 dialog 的按钮
actions: [
FlatButton(
child: Text(‘OK’),
// 用户点击按钮后,关闭弹框
onPressed: () => Navigator.pop(context),
)
],
);
}
);
}
)
],
);
}

@override
void dispose() {
super.dispose();
editController.dispose();
}
}

最简单的布局——Container、Padding 和 Center:

我们经常说,Flutter 里面所有的东西都是 Widget,所以,布局也是 Widget。

控件 Container 可以让我们设置一个控件的尺寸、背景、margin 等:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text(‘text’),
padding: EdgeInsets.all(8.0),
margin: EdgeInsets.all(4.0),
width: 80.0,
decoration: BoxDecoration(
// 背景色
color: Colors.grey,
// 圆角
borderRadius: BorderRadius.circular(5.0),
),
);
}
}

如果我们只需要 padding,可以使用控件 Padding:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8.0),
child: Text(‘text’),
);
}
}

Center 就跟它的名字一样,把一个控件放在中间:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
margin: EdgeInsets.all(4.0),
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
// 背景色
color: Colors.grey,
// 圆角
borderRadius: BorderRadius.circular(5.0),
),

// 把文本放在 Container 的中间
child: Center(
child: Text(‘text’),
),
);
}
}

水平、竖直布局和 Expand

我们经常说,Flutter 里面所有的东西都是 Widget,所以,布局也是 Widget。水平布局我们可以使用 Row,竖直布局使用 Column。

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
// 只有一个子元素的 widget,一般使用 child 参数来设置;Row 可以包含多个子控件,
// 对应的则是 children。
children: [
Text(‘text1’),
Text(‘text2’),
Text(‘text3’),
Text(‘text4’),
],
);
}
}

Column 的使用是一样的:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(‘text1’),
Text(‘text2’),
Text(‘text3’),
Text(‘text4’),
],
);
}
}

关于 Expand 控件,我们来看看 TextField 的那个例子:

class MessageForm extends StatefulWidget {
@override
State createState() {
return _MessageFormState();
}
}

class _MessageFormState extends State {
var editController = TextEditingController();

@override
Widget build(BuildContext context) {
return Row(
children: [
// 占满一行里除 RaisedButton 外的所有空间
Expanded(
child: TextField(
controller: editController,
),
),
RaisedButton(
child: Text(“click”),
onPressed: () => print(‘text inputted: ${editController.text}’),
)
],
);
}

@override
void dispose() {
super.dispose();
editController.dispose();
}
}

这里通过使用 Expand,TextField 才能够占满一行里除按钮外的所有空间。此外,当一行/列里有多个 Expand 时,我们还可以通过设置它的 flex 参数,在多个 Expand 之间按比例划分可用空间。

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
// 占一行的 2/3
flex: 2,
child: RaisedButton(child: Text(‘btn1’),),
),
Expanded(
// 占一行的 1/3
flex: 1,
child: RaisedButton(child: Text(‘btn2’),),
),
],
);
}
}

Stack 布局

有些时候,我们可能会希望一个控件叠在另一个控件的上面。于是,Stack 应运而生:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
children: [
Text(‘foobar’),
Text(‘barfoo’),
],
);
}
}

默认情况下,子控件都按 Stack 的左上角对齐,于是,上面的两个文本完全一上一下堆叠在一起。我们还可以通过设置 alignment 参数来改变这个对齐的位置:

class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
// Aligment 的取值范围为 [-1, 1],Stack 中心为 (0, 0),
// 这里设置为 (-0.5, -0.5) 后,可以让文本对齐到 Container 的 1/4 处
alignment: const Alignment(-0.5, -0.5),
children: [
Container(
width: 200.0,
height: 200.0,
color: Colors.blue,
),
Text(‘foobar’),
],
);
}
}

效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

screenshot-stack

通过组合 Row/Column 和 Stack,已经能够完成绝大部分的布局了,所以 Flutter 里没有相对布局之类的东西。更多的 Flutter 控件,读者可以参考 flutter.io/widgets/

示例一

在这一节里,我们综合前面所学的知识,来实现下面这个界面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

lakes-diagram

展示图片

  1. 把图片 lake 放到项目根目录的 images 文件夹下(如果没有,你需要自己创建一个)

  2. 修改 pubspec.yaml,找到下面这个地方,然后把图片加进来

flutter:

# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true

# To add assets to your application, add an assets section, like this:
# assets:
#  - images/a_dot_burr.jpeg
#  - images/a_dot_ham.jpeg

修改后如下:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

如果你进阶的路上缺乏方向,可以点击我的【Github】加入我们的圈子和安卓开发者们一起学习交流!
以下全部内容都可以在GitHub中获取!

  • Android进阶学习全套手册

    img

  • Android对标阿里P7学习视频

    img

  • BATJ大厂Android高频面试题

    img

最后,借用我最喜欢的乔布斯语录,作为本文的结尾:

人这一辈子没法做太多的事情,所以每一件都要做得精彩绝伦。
你的时间有限,所以不要为别人而活。不要被教条所限,不要活在别人的观念里。不要让别人的意见左右自己内心的声音。
最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实想法,其他一切都是次要。

-YmoeS9IU-1711182974467)]

如果你进阶的路上缺乏方向,可以点击我的【Github】加入我们的圈子和安卓开发者们一起学习交流!
以下全部内容都可以在GitHub中获取!

  • Android进阶学习全套手册

    [外链图片转存中…(img-1JyWMsJV-1711182974468)]

  • Android对标阿里P7学习视频

    [外链图片转存中…(img-BQZehWBL-1711182974468)]

  • BATJ大厂Android高频面试题

    [外链图片转存中…(img-UQtGb7Gq-1711182974468)]

最后,借用我最喜欢的乔布斯语录,作为本文的结尾:

人这一辈子没法做太多的事情,所以每一件都要做得精彩绝伦。
你的时间有限,所以不要为别人而活。不要被教条所限,不要活在别人的观念里。不要让别人的意见左右自己内心的声音。
最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实想法,其他一切都是次要。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/455478
推荐阅读
相关标签
  

闽ICP备14008679号