【问题标题】:How to present an empty view in flutter?如何在颤动中呈现一个空视图?
【发布时间】:2019-04-26 13:52:14
【问题描述】:

如何在 Flutter 中呈现一个空视图,因为 Widget.build 无法返回 null 以指示没有要渲染的内容。

【问题讨论】:

  • 所以返回一个空的 ContainterMaterial 或类似的小部件..
  • 如果您需要占位符,请不要忘记有一个占位符小部件:youtube.com/watch?v=LPe56fezmoo

标签: flutter


【解决方案1】:

对于像我这样想知道什么是显示空小部件的“正确方法”的人 - 官方 Material 代码库使用这个:

Widget build(BuildContext context) {
  return SizedBox.shrink();
}

SizedBox.shrink() 是一个与ContainerMaterial 不同的小部件,它没有任何背景或任何装饰。如果不受父约束的影响,它将自身调整到尽可能小的区域。

【讨论】:

  • 基本上只返回SizedBox(width: 0, height: 0)
  • 这是唯一不会在列表视图中引发错误的答案
  • 尽管 SizedBox.shrink 很有用,但它仍然会在屏幕上占用一些空间,我宁愿说它就像 SizedBox(width: 5, height: 5)
  • 如果您使用 Column and Row,这将不起作用,它仍将计为 col 和 row 项
【解决方案2】:
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

    );
  }
}

您也可以简单地返回一个空的Container 并完全避免使用Scaffold。但是如果这是您应用中唯一的主要小部件,这将导致黑屏,如果您想防止黑背景,您可以设置Containercolor 属性。

例子:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white // This is optional
    );
  }
}

【讨论】:

    【解决方案3】:

    有很多可能的解决方案。喜欢

    1. Widget build(context) => Container();
      
    2. Widget build(context) => SizedBox();
      
    3. Widget build(context) => Scaffold();
      

    【讨论】:

      【解决方案4】:

      性能

      容器 = 166,173 毫秒

      SizedBox.shrink = 164,523 毫秒

      自己动手

      main() async {
        testWidgets('test', (WidgetTester tester) async {
          await tester.pumpWidget( Container());
          final Stopwatch timer = new Stopwatch()..start();
          for (int index = 0; index < 5000000; index += 1) {
            await tester.pump();
          }
          timer.stop();
          debugPrint('Time taken: ${timer.elapsedMilliseconds}ms');
        });
      }
      

      【讨论】:

      • 哇,好研究
      • 如果您不知道该代码放在哪里,请按双档并打开widget_test.dart
      【解决方案5】:

      当构建函数返回 null 时,flutter 的错误信息是:

      构建函数绝不能返回 null。要返回导致建筑小部件填满可用空间的空白空间,请返回“new Container()”。要返回占用尽可能少空间的空白空间,请返回“new Container(width: 0.0, height: 0.0)”。

      【讨论】:

      • 是的。如果我在零安全方案中运行应用程序,我会遇到这个问题。所以,我选择听从你的建议。
      【解决方案6】:

      这可能为时已晚,但所有这些解决方案都不适用于某些场景,例如玩 PopupMenuItems 或影响 UI 渲染!

      空安全更新

        [
          .
          .
          .
          if(condition)...[//Conditionally widget(s) here
            Something(...),
          ],
          .
          .
          .
      ],
      

      解决方案是在传递给渲染组件之前删除空项:

      Column(
        children: [
          Text('Title'),
          name != '' 
            ? Text(name) //show name
            : null // just pass a null we will filter it in next line!
        ].where((e) => e != null).toList()// Filter list and make it List again!
      )
      

      这样,我们可以有很多空,UI不会被任何空的Widget影响。

      PopupMenuButton 示例我们无法通过 SizedBox

      PopupMenuButton(
          icon: Icon(Icons.add),
          itemBuilder: (context) => [
              PopupMenuItem(
                  child: Row(children:[ Icon(Icons.folder), Text('So something')]),
                  value: 'do.something',
              ),
              1 > 2 //⚠️ A false condition
              ? PopupMenuItem(
                 child: Row(children: [ Icon(Icons.file_upload), Text('⚠️No way to display ?')]),
                  'no.way.to.display',
                )
              : null,// ⚠️ Passing null
              PopupMenuItem(
                 child: Row(children: [ Icon(Icons.file_upload), Text('Do something else')]),
                  'do.something.else',
              )
          ].where((e) => e != null).toList(),//ℹ️ Removing null items  
          onSelected: (item) {}
      )
      
      

      这可以用作extension的API:

      extension NotNulls on List {
        ///Returns items that are not null, for UI Widgets/PopupMenuItems etc.
        notNulls() {
          return where((e) => e != null).toList();
        }
      }
      
      //Usage:
      PopupMenuButton(
          icon: Icon(Icons.add),
          itemBuilder: (context) => [
              PopupMenuItem(
                  child: Row(children:[ Icon(Icons.folder), Text('So something')]),
                  value: 'do.something',
              ),
              1 > 2 //⚠️ A false condition
              ? PopupMenuItem(
                 child: Row(children: [ Icon(Icons.file_upload), Text('⚠️No way to display ?')]),
                  'no.way.to.display',
                )
              : null,// ⚠️ Passing null
              PopupMenuItem(
                 child: Row(children: [ Icon(Icons.file_upload), Text('Do something else')]),
                  'do.something.else',
              )
          ].notNulls(),//ℹ️ Removing null items  
          onSelected: (item) {}
      )
      
      
      

      【讨论】:

        【解决方案7】:

        不显示任何内容的推荐小部件是使用SizedBox

        SizedBox(
          width: 200.0,
          height: 300.0,
        )
        

        【讨论】:

        • 此建议的参考依据是什么?
        • 我花了很长时间才回复,但 SizedBox 已在第一方小部件(如 AppBar)中用于显示空白内容。
        【解决方案8】:

        我的问题非常相似,但我发现 ContainerSizedBox.shrink 仍然影响 UI(令人沮丧)。

        我得到的最佳解决方案是使用命名构造函数和初始化列表以不同方式构建它。例如:

        class MyWidget extends StatelessWidget {
            final String name = 'Default';
            final bool hasThing = true;
        
            MyWidget({this.name});
        
            MyWidget.withoutThing({this.name}) : hasThing = false;
        
            @override
            Widget build(BuildContext context) {
                //define widgets they have in common here (as many as possible)
                if (hasThing) {
                    return Widget(child: Thing(this.name));
                } else {
                    return Widget(child: WithoutThing(this.name));
                }
            }
        }
        

        并使用它:

        Center(child: MyWidget.withoutThing(name: 'Foo'),)//don't show thing
        

        Center(child: MyWidget(name: 'Foo'),)
        

        根据您的需要。

        有关初始化列表的更多信息:Colon after Constructor in dart

        【讨论】:

          【解决方案9】:

          Column里面我用的是SizedBox(height: 0.01)

          Column(
            children: [
              Text('Title'),
              name == ''
              ? SizedBox(height: 0.01) // show nothing
              : Text(name) // show name
            ]
          )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-03-31
            • 2012-06-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-27
            相关资源
            最近更新 更多