阅读 60

Flutter之widgets 响应式布局LayoutBuilder组件

响应式应用指的是应用的 UI 会随着屏幕或窗口的改变而改变,当同一个应用需要运行在不同种类的设备的时候(比如手表、手机、平板、笔记本或台式机电脑),当用户在笔记本或台式机上调整窗口大小,或者改变了手机或者平板的方向时,你的应用都需要相应的重新调整界面来做出响应。

LayoutBuilder

通过 LayoutBuilder,我们可以在布局过程中拿到父组件传递的约束信息,然后我们可以根据约束信息动态的构建不同的布局。

比如我们实现一个响应式的 Column 组件 ResponsiveColumn,它的功能是当当前可用的宽度小于 200 时,将子组件显示为一列,否则显示为两列。简单来实现一下:

class ResponsiveColumn extends StatelessWidget {   const ResponsiveColumn({Key? key, required this.children}) : super(key: key);     final List<Widget> children;     @override   Widget build(BuildContext context) {     // 通过 LayoutBuilder 拿到父组件传递的约束,然后判断 maxWidth 是否小于200     return LayoutBuilder(       builder: (BuildContext context, BoxConstraints constraints) {         if (constraints.maxWidth < 200) {           // 最大宽度小于200,显示单列           return Column(children: children, mainAxisSize: MainAxisSize.min);         } else {           // 大于200,显示双列           var _children = <Widget>[];           for (var i = 0; i < children.length; i += 2) {             if (i + 1 < children.length) {               _children.add(Row(                 children: [children[i], children[i + 1]],                 mainAxisSize: MainAxisSize.min,               ));             } else {               _children.add(children[i]);             }           }           return Column(children: _children, mainAxisSize: MainAxisSize.min);         }       },     );   } }     class LayoutBuilderRoute extends StatelessWidget {   const LayoutBuilderRoute({Key? key}) : super(key: key);     @override   Widget build(BuildContext context) {     var _children = List.filled(6, Text("A"));     // Column在本示例中在水平方向的最大宽度为屏幕的宽度     return Column(       children: [         // 限制宽度为190,小于 200         SizedBox(width: 190, child: ResponsiveColumn(children: _children)),         ResponsiveColumn(children: _children),         LayoutLogPrint(child:Text("xx")) // 下面介绍       ],     );   } } 复制代码

可以发现 LayoutBuilder 的使用很简单,但是不要小看它,因为它非常实用且重要,它主要有两个使用场景:

  • 可以使用 LayoutBuilder 来根据设备的尺寸来实现响应式布局。

  • LayoutBuilder 可以帮我们高效排查问题。比如我们在遇到布局问题或者想调试组件树中某一个节点布局的约束时 LayoutBuilder 就很有用。

打印布局时的约束信息

为了便于排错,我们封装一个能打印父组件传递给子组件约束的组件:

class LayoutLogPrint <T>extends StatelessWidget {   final Widget child;   final T? tag;   const LayoutLogPrint({Key? key, required this.child, this.tag}) : super(key: key);     @override   Widget build(BuildContext context) {     return LayoutBuilder(builder: (_,constraints){       // assert在编译release版本时会被去除       assert(() {         print('${tag ?? key ?? child}: $constraints');         return true;       }());       return child;     });   } } 复制代码

这样,我们就可以使用 LayoutLogPrint 组件树中任意位置的约束信息,比如:

LayoutLogPrint(child:Text("xx")) 复制代码

控制台输出:

图片.png

flutter: Text("xx"): BoxConstraints(0.0<=w<=393.0, 0.0<=h<=Indinity) 复制代码

可以看到 Text("xx") 的显示空间最大宽度为 393,最大高度为 Indinity 。

项目实用1

如果图片在使用过程中,不要求图片的完整性,可以进行拉伸,我们就会使用其属性fit为BoxFit.fill,使用这个属性后图片就可以进行拉伸处理。不过如果我们需求是宽占满整个屏幕,高度为自定义的高度,则简单的代码就很难实现了,如下:

Center(         child: Container(           child: Column(             children: <Widget>[               Image.network(                 "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1563774129262&di=a62f1daccb204945eafcfd5082b4ce98&imgtype=0&src=http%3A%2F%2Fimages.ali213.net%2Fpicfile%2Fpic%2F2012-11-27%2F927_one_piece18.jpg",                 fit: BoxFit.fill,                 height: 100,               ),               Text("图片"),             ],           ),         ),       ), 复制代码

运行效果:

图片.png

此时需要知道父级的宽度即可,此时便可以用LayoutBuilder进行包含:

LayoutBuilder(         builder: (context, constraints) {           return Center(             child: Container(               child: Column(                 children: <Widget>[                   Image.network(                     "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1563774129262&di=a62f1daccb204945eafcfd5082b4ce98&imgtype=0&src=http%3A%2F%2Fimages.ali213.net%2Fpicfile%2Fpic%2F2012-11-27%2F927_one_piece18.jpg",                     fit: BoxFit.fill,                     height: 100,                     width: constraints.maxWidth,                   ),                   Text("图片"),                 ],               ),             ),           );         },       ), 复制代码

图片.png

builder: (context, constraints){}中,context是父级的上下文,constraints为BoxConstraints类型,maxWidth为父级宽度,maxHeight为父级高度。

项目实用2

LayoutBuilder组件根据不同的屏幕尺寸显示不同的效果,如竖屏和横屏显示的样式不一样。

图片.png

图片.png

代码:

class WyLayoutBuilder extends StatelessWidget {   const WyLayoutBuilder({Key? key}) : super(key: key);   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: getAppBar("横竖屏输配"),       body: LayoutBuilder(         builder: (BuildContext context, BoxConstraints constraints) {           Color color = Colors.red;           double width = 100;           if (constraints.maxWidth > 414) {             color = Colors.blue;             width = 300;           }           return Container(             width: width,             height: 50,             color: color,           );         },       )       ,     );   } }


作者:风雨_83
链接:https://juejin.cn/post/7169396691085295629


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