阅读 93

图文并茂的Flutter布局和状态管理~

抽取Widget

打开我们上一篇的示例的代码,我们发现main.dart里面有很多Widget。我们可以抽取一下代码,也就是解耦。

  • 抽取listView: 右键选中New->Dart File,创建一个新的listview.dart文件, 输入s就可以快速联想出来有状态和无状态的两种widget的代码块

image.png

选中stless回车

class  extends StatelessWidget {   const ({Key? key}) : super(key: key);   @override   Widget build(BuildContext context) {     return Container();   } } 复制代码

extends前面的类型为class ListViewDemo extends StatelessWidget 删除const ({Key? key}) : super(key: key);我们这里暂时用不到。此时这个文件中的代码就成为了

import 'package:flutter/material.dart'; import 'model/car.dart'; class ListViewDemo extends StatelessWidget {   Widget _itemForRow(BuildContext context, int index) {     return Container(         color: Colors.white,         margin: EdgeInsets.all(10),         child: Column(           children: [             Image.network(datas[index].imageUrl!),             Text(datas[index].name!)           ],         )     );   }   @override   Widget build(BuildContext context) {     return ListView.builder(       itemBuilder: _itemForRow,       itemCount: datas.length,     );   } } 复制代码

然后把main.dart的关于ListView全部剪切到这里,此时主工程的Home的body修改为当前的ListViewDemo()

import 'package:flutter/material.dart'; import 'package:hello_flutter/base_widget.dart'; import 'package:hello_flutter/listview.dart'; void main() => runApp(App()); class App extends StatelessWidget {   @override   Widget build(BuildContext context) {     return MaterialApp(       home: Home(),     );   } } class Home extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Scaffold(       backgroundColor: Colors.grey,       appBar: AppBar(         title: Text(             'flutterDemo'         ),       ),       body: ListViewDemo(),     );   } } 复制代码

  • 抽取model,把main.dart文件中的List<Car> datas数据源放置到当前的car.dart文件中。这样主文件中的代码就比较精简了。

  • 同理,把最开始创建的MyWidget也抽取出去,这样在main.dart如果想要切换使用的话,只需要修改对应的组件构造方法即可。

常用Widget

  1. Text组件: String拼接使用$

import 'package:flutter/material.dart'; class TextDemo extends StatelessWidget {   final TextStyle _textStyle = TextStyle(     fontSize: 16.0,     backgroundColor: Colors.red,   );   final String _pre = '前缀';   final String _end = '后缀';   @override   Widget build(BuildContext context) {     return Text('$_pre 1. 抽取model:把main.dart文件中的List<Car> datas数据源放置到当前的car.dart文件中。这样主文件中的代码就比较精简了。3. 同理,把最开始创建的MyWidget也抽取出去,这样在main.dart如果想要切换使用的话,只需要修改对应的组件构造方法即可。$_end',     textAlign: TextAlign.center,     style: _textStyle);  // 这个TextStyle的构造也可以抽取出去   } } 复制代码

运行之后:

image.png

还可以设置最大行数,以及多余的行用省略号表示

Text(     maxLines: 3, // 最大3行      overflow: TextOverflow.ellipsis, // 超过3行后缀省略 ); 复制代码

image.png

  1. 富文本RichText组件:这个RichText组件有一个TextSpan可以嵌套使用,针对不同的文本设置不同的style

  @override   Widget build(BuildContext context) {     return RichText(text: TextSpan(       children: <TextSpan>[         TextSpan(             text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',             style: TextStyle(                 fontSize: 30,                 color: Colors.yellow             )         ),         TextSpan(             text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',             style: TextStyle(                 fontSize: 20,                 color: Colors.red             )         ),         TextSpan(             text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',             style: TextStyle(                 fontSize: 40,                 color: Colors.purpleAccent             )         ),       ],     ));   } 复制代码

image.png

3.Container组件:这个组件在布局的时候经常使用。因为它有一个childen而且会自适应布局。搭配着Row这个组件就可以无限套娃当然还有上一篇介绍的Column

class TextDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       child: Row(         children: [           Container(             color: Colors.red,             child: Icon(Icons.add),             //padding: EdgeInsets.all(30) , // 内边距            // margin: EdgeInsets.all(20), // 外边距           )         ],       ),     );   } } 复制代码

这里的padding是内边距,如果没有设置的话是这样的

image.png

打开padding的注释可以清楚的看到是图片的内边距

image.png

继续打开margin的注释,这样一对比就能看出,margin是图片的外边距。

image.png

Flutter布局之Row

弹性盒子布局:横向Row、纵向Column、折叠Stack。在flutter中Alignment的中心点即为父控件的center

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       child: Text('Layout Demo'),       alignment: Alignment(0,0), // [-1,1]     );   } } 复制代码

image.png

我们研究下搭配着row使用的对齐方式,为了方便观察,给每个Icon包装了一层Container用来设置颜色

class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(0,0),       child: Row(         children: [           Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),           Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),           Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),           Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),         ],       ),     );   } } 复制代码

image.png

修改Alignment(-1,-1)的x坐标:

image.png

修改Alignment(-1,-1)的y坐标:

image.png

此时修改alignment: Alignment(-1,0)让它的横坐标修改为-1或者1都对这个没有影响。但是修改纵坐标y的话:y = -1时图像跑到了最上面,y = 1时图像跑到了最下面,所以说使用Row布局的时候,修改x的坐标不会产生影响。

Flutter布局之Column

此时修改下布局的方式

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(1,1),       child: Column(         children: [           Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),           Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),           Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),           Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),         ],       ),     );   } } 复制代码

image.png image.png

同理,如果搭配着Column来布局的话,此时修改alignment: Alignment(-1,0)让它的纵坐标修改为-1或者1都对这个没有影响。但是修改横坐标x的话:x = -1时图像跑到了最左面,x = 1时图像跑到了最右面,所以说使用Column布局的时候,修改y的坐标不会产生影响。

Flutter布局之Stack

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(0,0),       child: Stack(         children: [           Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),           Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),           Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),           Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),         ],       ),     );   } } 复制代码

image.png

主轴和交叉轴

使用以上三种方向布局的时候我们需要知道主轴!主轴属性:居中、开始、结束 主轴方向:

  • 横向Row -> 右边

  • 纵向Column -> 下

  • 多层Stack -> 外

  1. 主轴添加属性(start/center/end):默认是从左边开始,如果想从右边开始我们可以添加主轴属性mainAxisAlignment: MainAxisAlignment.end。同理设置start就是左边,center就是中间

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(0,0),       child: Row(         mainAxisAlignment: MainAxisAlignment.end, // 已结束位置         children: [           Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),           Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),           Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),           Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),         ],       ),     );   } } 复制代码

设置主轴方向之后运行效果:

image.png

  1. 主轴添加属性MainAxisAlignment.spaceBetween:剩下的空间平均分配到小部件之间。

image.png

  1. 主轴添加属性MainAxisAlignment.spaceAround:剩下的空间平均分配到小部件周围。

image.png

  1. 主轴添加属性MainAxisAlignment.spaceEvenly:剩下的空间和小部件一起平均分。

image.png

  1. 交叉轴也就是y轴CrossAxisAlignment也有属性(start/center/end),除了基本的三个之外还有一个CrossAxisAlignment.baseline,使用Text组件的时候可以看的比较明显就是文字底部对齐,一般搭配着textBaseline 一起使用,不然会报错

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(0,0),       child: Row(         mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 已结束位置         crossAxisAlignment: CrossAxisAlignment.baseline,         textBaseline: TextBaseline.alphabetic,         children: [           Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),           Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),           Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),           Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),         ],       ),     );   } } 复制代码

image.png

Expanded

使用Expand的小组件会占满当前的主轴方法,在主轴方向不会剩下空隙,当横线布局不够用的时候会自动换行。

import 'package:flutter/material.dart'; class LayoutDemo extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Container(       alignment: Alignment(0,0),       child: Row(         children: [           Expanded(child: Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,)),           Expanded(child: Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,)),           Expanded(child: Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,)),           Expanded(child: Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,)),         ],       ),     );   } } 复制代码

image.png


作者:weak_PG
链接:https://juejin.cn/post/7023684597003059231


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐