Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考

Posted nesger

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考相关的知识,希望对你有一定的参考价值。

技术图片

背景

在进行 Flutter UI 开发的时候,控制台报出了下面错误:

flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY >╞═════════════════════════════════════════════════════════
flutter: The following message was thrown during layout:
flutter: A RenderFlex overflowed by 826 pixels on the right.

界面的体现就是黄色区域。

这里的代码是在上一篇的基础上返回下面的 Widget:

return Row(
      children: <Widget>[
        Image.network(
            'https://upload-images.jianshu.io/upload_images/5361063-cfad13c672a06084.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240')
      ],
    );

模拟器效果如下:

技术图片

思考

其实一般遇到这种情况,都应该考虑一下是否这样布局合理。

上面这个我们只是举个例子,因为一般如果只有一张图片,是不需要给他套一层 Row 的。

因为情况比较多,这里假设有时候真的就需要这么处理,怎么办?

解决方法

如果你某个 Widget 出现了上面的问题,而且真的不是布局问题,而是真的就是有可能出现这种情况,但是你不希望 debug 模式显示这个错误,那么可以给他套一层 Expanded。

官网有如下说明:

A widget that expands a child of a?Row,?Column, or?Flex.

Using an?Expanded?widget makes a child of a?Row,?Column, or?Flex?expand to fill the available space in the main axis (e.g., horizontally for a?Row?or vertically for a?Column). If multiple children are expanded, the available space is divided among them according to the?flex?factor.

所以对于 Row、Column 以及 Flex 都可以用 Expanded 来解决子组件报上面错误问题。

所以这里可以修改为

return Row(
      children: <Widget>[
        Expanded(
          child: Image.network(
              'https://upload-images.jianshu.io/upload_images/5361063-cfad13c672a06084.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'),,
        )
      ],
    );

效果如下:

技术图片

Expanded 妙用

Expanded 除了可以解决上面的问题之外,还有一个妙用就是比例布局。

什么意思呢?

我们写下代码,然后给下效果图你就懂了。

return Column(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.red,
          ),
        ),
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.blue,
          ),
        ),
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.grey,
          ),
        ),
      ],
    );

效果图如下:

技术图片

可以看出 Expanded 的 flex 属性会按比例布局。

Sample

我们来实现一个简单的 UI。

如下图,可以看到是一个网络错误时,点击重试的页面。

技术图片

假设你之前习惯了 sketch 边距开发,你看到这个页面,就直接根据边距进行开发,写出了下面的代码。

实现方式一:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        backgroundColor: Color(0xFFF0F1F0),
        body: Center(
          child: _buildWidget(),
        ),
      ),
    );
  }

  Widget _buildWidget() {
    return Container(
      child: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.only(left: 97.0, right: 97.0, top: 125),
            child: Image.asset('assets/images/refresh.png', width: 49, height: 44,),
          ),
          SizedBox(
            height: 42.0,
          ),
          FlatButton(
              padding: const EdgeInsets.symmetric(horizontal: 50.0),
              //注意这里 alpha 最大值是 255, sketch 上面最大值是 100
              color: Color.fromARGB(255, 13, 46, 172),
              //这里 onPressed 不能为 null,如果写 null 会怎样,大家可以试下~
              onPressed: (){},
              child: Text(
                //演示而已,实际开发需要多语言
                '刷新',
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 12,
                    fontWeight: FontWeight.w600
                ),
              )
          )
        ],
      ),
    );
  }

}

效果如下:

技术图片

你会发现这种实现方式的适配性会很差,而且可能出现上面的问题。

因此我们看下使用 Expanded 如何实现。

观察一下,我们发现界面大概可以分成 3 块。

每一块占的比例差不多,因此可以如下实现。

实现方式二:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        backgroundColor: Color(0xFFF0F1F0),
        body: Center(
          child: _buildWidget(),
        ),
      ),
    );
  }

  Widget _buildWidget() {
    return Container(
      child: Column(
        children: <Widget>[
          Expanded(
            flex: 1,
            child: Container(),
          ),
          Image.asset('assets/images/refresh.png', width: 49, height: 44,),
          SizedBox(
            height: 42.0,
          ),
          FlatButton(
              padding: const EdgeInsets.symmetric(horizontal: 50.0),
              //注意这里 alpha 最大值是 255, sketch 上面最大值是 100
              color: Color.fromARGB(255, 13, 46, 172),
              //这里 onPressed 不能为 null,如果写 null 会怎样,大家可以试下~
              onPressed: (){},
              child: Text(
                //演示而已,实际开发需要多语言
                '刷新',
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 12,
                    fontWeight: FontWeight.w600
                ),
              )
          ),
          Expanded(
            flex: 1,
            child: Container(),
          ),
        ],
      ),
    );
  }

}

效果如下:

技术图片

其实,看到上面用到的 Column,我们可以直接利用上次说到的一个属性,就可以很巧妙的实现适配。

实现方式三:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Color(0xFFF0F1F0),
        body: Center(
          child: _buildWidget(),
        ),
      ),
    );
  }

  Widget _buildWidget() {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Image.asset(
            'assets/images/refresh.png',
            width: 49,
            height: 44,
          ),
          SizedBox(
            height: 42.0,
          ),
          FlatButton(
              padding: const EdgeInsets.symmetric(horizontal: 50.0),
              //注意这里 alpha 最大值是 255, sketch 上面最大值是 100
              color: Color.fromARGB(255, 13, 46, 172),
              //这里 onPressed 不能为 null,如果写 null 会怎样,大家可以试下~
              onPressed: () {},
              child: Text(
                //演示而已,实际开发需要多语言
                '刷新',
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 12,
                    fontWeight: FontWeight.w600),
              )),
        ],
      ),
    );
  }
}

效果如下:

技术图片

其中实现方式一只是说明,实际开发不推荐。

实现方式二和实现方式三都可以,推荐方式三。

相关代码及 sketch 图都放到了 GitHub 仓库??:
https://github.com/nesger/FlutterSample

其中分支 feature/ui-refresh-one 是实现方式一。
分支 feature/ui-refresh-two 是实现方式二。
分支 feature/ui-refresh-three 是实现方式三。

这里按钮宽度和高度没有指定,大家可以根据情况确定是否指定哈~

总之就是:

实现方式千万条,合适第一条。
适配不精确,测试两行泪。

更多阅读:
Flutter 即学即用系列博客——01 环境搭建
Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
Flutter 即学即用系列博客——04 Flutter UI 初窥
Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
Flutter 即学即用系列博客——06 超实用 Widget 集锦

技术图片

以上是关于Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 即学即用系列博客——04 Flutter UI 初窥

《AngularJS即学即用》读书笔记

Node 即学即用 笔记 思维导图

Timus 1545. Hieroglyphs Trie的即学即用 实现字典提示功能

5个Excel序号填充技巧,简单明了,即学即用

《Postgre SQL 即学即用 (第三版)》 分享 pdf下载