226

在 Android 中,每个View子类都有一个setVisibility()方法可以让您修改View对象的可见性

设置可见性有 3 个选项:

  • ViewVisible:在布局内渲染可见
  • 不可见:隐藏View,但留下一个与View可见时所占据的间隙相同的间隙
  • 消失:隐藏View,并将其从布局中完全删除。就好像它heightwidth曾经0dp

Flutter 中的 Widgets 是否有与上述等价的东西?

快速参考: https ://developer.android.com/reference/android/view/View.html#attr_android:visibility

4

17 回答 17

380

定义:

不可见:小部件占用屏幕上的物理空间,但对用户不可见。这可以使用Visibility小部件来实现。

Gone:小部件不占用任何物理空间并且完全消失了。这可以使用Visibility,ifif-else条件来实现。

看不见的例子:

Visibility(
  child: Text("Invisible"),
  maintainSize: true, 
  maintainAnimation: true,
  maintainState: true,
  visible: false, 
),

过去的例子:

Visibility(
  child: Text("Gone"),
  visible: false,
),

使用if

  • 对于一个孩子:

    Column(
      children: <Widget>[
        Text('Good Morning'), // Always visible
        if (wishOnePerson) Text(' Mr ABC'), // Only visible if condition is true
      ],
    ) 
    
  • 对于多个孩子:

    Column(
      children: [
        Text('Good Morning'), // Always visible
        if (wishAll) ... [ // These children are only visible if condition is true
          Text('Mr ABC'),
          Text('Mr DEF'),
          Text('Mr XYZ'),
        ],
      ],
    )
    

使用if-else

  • 对于一个孩子:

    Column(
      children: <Widget>[
        // Only one of them is visible based on 'isMorning' condition
        if (isMorning) Text('Good Morning')
        else Text ('Good Evening'),
      ],
    ) 
    
  • 对于多个孩子:

    Column(
      children: [
        // Only one of the children will be shown based on `beforeSunset` condition
        if (beforeSunset) ... [
          Text('Good morning'),
          Text('Good afternoon'),
        ] else ... [
          Text('Good evening'),
          Text('Good night'),
        ],
      ],
    )
    
于 2018-10-29T11:28:49.167 回答
125

更新:由于编写了此答案,Visibility因此引入并提供了此问题的最佳解决方案。


您可以使用Opacitywith anopacity:0.0绘制隐藏元素但仍占用空间。

要使其不占用空间,请将其替换为空的Container().

编辑:要将其包装在 Opacity 对象中,请执行以下操作:

            new Opacity(opacity: 0.0, child: new Padding(
              padding: const EdgeInsets.only(
                left: 16.0,
              ),
              child: new Icon(pencil, color: CupertinoColors.activeBlue),
            ))

Google Developers 关于不透明度的快速教程:https ://youtu.be/9hltevOHQBw

于 2017-06-12T00:24:22.490 回答
75

与问题协作并展示用空替换它的示例Container()

这是下面的示例:

在此处输入图像描述

import "package:flutter/material.dart";

void main() {
  runApp(new ControlleApp());
}

class ControlleApp extends StatelessWidget { 
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "My App",
      home: new HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  HomePageState createState() => new HomePageState();
}

class HomePageState extends State<HomePage> {
  bool visibilityTag = false;
  bool visibilityObs = false;

  void _changed(bool visibility, String field) {
    setState(() {
      if (field == "tag"){
        visibilityTag = visibility;
      }
      if (field == "obs"){
        visibilityObs = visibility;
      }
    });
  }

  @override
  Widget build(BuildContext context){
    return new Scaffold(
      appBar: new AppBar(backgroundColor: new Color(0xFF26C6DA)),
      body: new ListView(
        children: <Widget>[
          new Container(
            margin: new EdgeInsets.all(20.0),
            child: new FlutterLogo(size: 100.0, colors: Colors.blue),
          ),
          new Container(
            margin: new EdgeInsets.only(left: 16.0, right: 16.0),
            child: new Column(
              children: <Widget>[
                visibilityObs ? new Row(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: <Widget>[
                    new Expanded(
                      flex: 11,
                      child: new TextField(
                        maxLines: 1,
                        style: Theme.of(context).textTheme.title,
                        decoration: new InputDecoration(
                          labelText: "Observation",
                          isDense: true
                        ),
                      ),
                    ),
                    new Expanded(
                      flex: 1,
                      child: new IconButton(
                        color: Colors.grey[400],
                        icon: const Icon(Icons.cancel, size: 22.0,),
                        onPressed: () {
                          _changed(false, "obs");
                        },
                      ),
                    ),
                  ],
                ) : new Container(),

                visibilityTag ? new Row(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: <Widget>[
                    new Expanded(
                      flex: 11,
                      child: new TextField(
                        maxLines: 1,
                        style: Theme.of(context).textTheme.title,
                        decoration: new InputDecoration(
                          labelText: "Tags",
                          isDense: true
                        ),
                      ),
                    ),
                    new Expanded(
                      flex: 1,
                      child: new IconButton(
                        color: Colors.grey[400],
                        icon: const Icon(Icons.cancel, size: 22.0,),
                        onPressed: () {
                          _changed(false, "tag");
                        },
                      ),
                    ),
                  ],
                ) : new Container(),
              ],
            )
          ),
          new Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new InkWell(
                onTap: () {
                  visibilityObs ? null : _changed(true, "obs");
                },
                child: new Container(
                  margin: new EdgeInsets.only(top: 16.0),
                  child: new Column(
                    children: <Widget>[
                      new Icon(Icons.comment, color: visibilityObs ? Colors.grey[400] : Colors.grey[600]),
                      new Container(
                        margin: const EdgeInsets.only(top: 8.0),
                        child: new Text(
                          "Observation",
                          style: new TextStyle(
                            fontSize: 12.0,
                            fontWeight: FontWeight.w400,
                            color: visibilityObs ? Colors.grey[400] : Colors.grey[600],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
              new SizedBox(width: 24.0),
              new InkWell(
                onTap: () {
                  visibilityTag ? null : _changed(true, "tag");
                },
                child: new Container(
                  margin: new EdgeInsets.only(top: 16.0),
                  child: new Column(
                    children: <Widget>[
                      new Icon(Icons.local_offer, color: visibilityTag ? Colors.grey[400] : Colors.grey[600]),
                      new Container(
                        margin: const EdgeInsets.only(top: 8.0),
                        child: new Text(
                          "Tags",
                          style: new TextStyle(
                            fontSize: 12.0,
                            fontWeight: FontWeight.w400,
                            color: visibilityTag ? Colors.grey[400] : Colors.grey[600],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
            ],
          )                    
        ],
      )
    );
  }
}
于 2017-09-09T02:43:18.117 回答
39

Flutter 现在包含一个可见性小部件,您应该使用它来显示/隐藏小部件。该小部件还可以通过更改替换用于在 2 个小部件之间切换。

这个小部件可以实现任何可见、不可见、消失等状态。

    Visibility(
      visible: true //Default is true,
      child: Text('Ndini uya uya'),
      //maintainSize: bool. When true this is equivalent to invisible;
      //replacement: Widget. Defaults to Sizedbox.shrink, 0x0
    ),
于 2019-01-10T05:16:30.667 回答
30

试试Offstage小部件

如果属性offstage:true不占用物理空间且不可见,

如果属性offstage:false它将占据物理空间并且可见

Offstage(
   offstage: true,
   child: Text("Visible"),
),
于 2019-03-08T12:34:48.077 回答
15

您可以使用名为 (Visibility) 的新小部件封装代码中的任何小部件,这是您希望它不可见的小部件最左侧的黄色灯

示例:假设您想让一行不可见:

  1. 单击灯并选择(使用小部件包装)
  2. 将小部件重命名为可见性
  3. 添加可见属性并将其设置为false
  4. 新创建的widget(Visibility Widget)的Child是你希望它不可见的Widget

              Visibility(
                  visible: false,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      SizedBox(
                        width: 10,
                      ),
                      Text("Search",
                        style: TextStyle(fontSize: 20
                        ),),
                    ],
                  ),
                ),
    

我希望它会在未来帮助某人

于 2020-05-27T18:20:27.987 回答
12
bool _visible = false;

 void _toggle() {
    setState(() {
      _visible = !_visible;
    });
  }

onPressed: _toggle,

Visibility(
            visible:_visible,
            child: new Container(
            child: new  Container(
              padding: EdgeInsets.fromLTRB(15.0, 0.0, 15.0, 10.0),
              child: new Material(
                elevation: 10.0,
                borderRadius: BorderRadius.circular(25.0),
                child: new ListTile(
                  leading: new Icon(Icons.search),
                  title: new TextField(
                    controller: controller,
                    decoration: new InputDecoration(
                        hintText: 'Search for brands and products', border: InputBorder.none,),
                    onChanged: onSearchTextChanged,
                  ),
                  trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
                    controller.clear();
                    onSearchTextChanged('');
                  },),
                ),
              ),
            ),
          ),
          ),
于 2019-05-21T07:03:21.190 回答
10

更新

Flutter 现在有一个可见性小部件。要实施您自己的解决方案,请从以下代码开始。


自己制作一个小部件。

显示隐藏

class ShowWhen extends StatelessWidget {
  final Widget child;
  final bool condition;
  ShowWhen({this.child, this.condition});

  @override
  Widget build(BuildContext context) {
    return Opacity(opacity: this.condition ? 1.0 : 0.0, child: this.child);
  }
}

显示/删除

class RenderWhen extends StatelessWidget {
  final Widget child;
  final bool condition;
  RenderWhen({this.child, this.show});

  @override
  Widget build(BuildContext context) {
    return this.condition ? this.child : Container();
  }
}

顺便问一下,上面的小部件有没有更好的名字?

更多阅读

  1. 关于如何制作可见性小部件的文章。
于 2018-11-30T00:44:00.423 回答
9

Flutter 1.5Dart 2.3中,可见性消失了,您可以通过在集合中使用 if 语句来设置可见性,而无需使用容器。

例如

child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
              Text('This is text one'),
              if (_isVisible) Text('can be hidden or shown'), // no dummy container/ternary needed
              Text('This is another text'),
              RaisedButton(child: Text('show/hide'), onPressed: (){
                  setState(() {
                    _isVisible = !_isVisible; 
                  });
              },)

          ],
        )
于 2019-05-10T20:13:08.320 回答
7

初学者也试试这个。

class Visibility extends StatefulWidget {
  @override
  _VisibilityState createState() => _VisibilityState();
}

class _VisibilityState extends State<Visibility> {
  bool a = true;
  String mText = "Press to hide";

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "Visibility",
      home: new Scaffold(
          body: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new RaisedButton(
                onPressed: _visibilitymethod, child: new Text(mText),),
                a == true ? new Container(
                width: 300.0,
                height: 300.0,
                color: Colors.red,
              ) : new Container(),
            ],
          )
      ),
    );
  }

  void _visibilitymethod() {
    setState(() {
      if (a) {
        a = false;
        mText = "Press to show";
      } else {
        a = true;
        mText = "Press to hide";
      }
    });
  }
}
于 2018-06-27T06:23:33.067 回答
7

正如@CopsOnRoad 已经强调的那样,您可以使用可见性小部件。但是,如果你想保持它的状态,例如,如果你想构建一个viewpager并根据页面使某个按钮出现和消失,你可以这样做

void checkVisibilityButton() {
  setState(() {
  isVisibileNextBtn = indexPage + 1 < pages.length;
  });
}    

 Stack(children: <Widget>[
      PageView.builder(
        itemCount: pages.length,
        onPageChanged: (index) {
          indexPage = index;
          checkVisibilityButton();
        },
        itemBuilder: (context, index) {
          return pages[index];
        },
        controller: controller,
      ),
      Container(
        alignment: Alignment.bottomCenter,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Visibility(
              visible: isVisibileNextBtn,
              child: "your widget"
            )
          ],
        ),
      )
    ]))
于 2019-07-26T18:04:52.397 回答
6

恕我直言,如果您不需要显示小部件,则在 Flutter 中不需要可见性属性或特殊小部件 - 只是不要将其添加到小部件树或用空小部件替换它:

  @override
  Widget build(BuildContext context) {
    return someFlag ? Text('Here I am') : SizedBox();
  }

我认为 Visibility 小部件存在的原因是因为有很多人问:) 人们习惯于对某些属性控制的元素进行可见性

于 2021-03-02T14:20:36.407 回答
4

在 Flutter 中有很多不同的方法可以实现这一点。在我解释它们之前,我将首先提供等效于Android原生的“invisible”和“gone”的快速解决方案:

View.INVISIBLE:

Opacity(
  opacity: 0.0,
  child: ...
)

查看.GONE:

Offstage(
  child: ...
)

现在让我们比较这些方法和其他方法:

不透明度

此小部件将不透明度(alpha)设置为您想要的任何内容。将其设置0.0为 比将其设置为 稍微不那么明显0.1,因此希望这很容易理解。小部件仍将保持其大小并占据相同的空间,并保持每个状态,包括动画。由于它留下了空隙,用户仍然可以触摸或点击它。(顺便说一句,如果你不想让人们触摸一个不可见的按钮,你可以用一个IgnorePointer小部件来包装它。)

台下

此小部件隐藏子小部件。您可以将其想象为将小部件放在“屏幕之外”,这样用户就不会看到它。小部件仍然通过颤动管道中的所有内容,直到它到达最后的“绘画”阶段,它根本不绘画任何东西。这意味着它将保留所有状态和动画,但不会在屏幕上呈现任何内容。此外,它在布局时也不会占用任何空间,不留空隙,用户自然无法点击。

能见度

为了您的方便,这个小部件结合了上述(以及更多)。它具有 、 、 等参数maintainStatemaintainAnimation根据maintainSizemaintainInteractivity设置这些属性的方式,它从以下内容中决定:

  1. 如果你想保持状态,它会用 anOpacity或 an包裹孩子,这Offstage取决于你是否也想保持大小。此外,除非您愿意,否则maintainInteractivity它还会IgnorePointer为您包装一个,因为单击透明按钮有点奇怪。

  2. 如果你根本不想maintainState,它直接用childa替换它,SizedBox所以它完全消失了。您可以使用该属性将空白更改为SizedBox您想要的任何内容replacement

删除小部件

如果您不需要维护状态等,通常建议从树中完全删除小部件。例如,您可以使用if (condition)来决定是否在列表中包含一个小部件,或者直接condition ? child : SizedBox()用 a 替换它SizedBox。这避免了不必要的计算,并且是最好的性能。

于 2021-10-08T06:04:20.153 回答
1

有条件地添加/删除小部件

要包含/排除小部件:

if (this.isLuckyTime) TextButton(
 child: Text('I am feeling lucky')
)

如果您想让小部件不可见但仍保持其大小,则将其包装到<Visibility>并设置maintainSize: true. 如果它是有状态的并且您需要保持它的状态,那么还要添加maintainState: true.

动画小部件淡入淡出

要使小部件平滑地淡入和淡出,您可以使用AnimatedOpacity

AnimatedOpacity(
   opacity: this.isLuckyTime ? 1.0 : 0.0,
   duration: Duration(milliseconds: 500),
   child: Text('I am feeling lucky')
)

专门针对来自原生 android 的开发人员:可能值得一提的是,您从不显示/隐藏小部件,您可以使用或不使用您需要的小部件来重绘 UI:

声明式 UI状态管理简介简单的应用状态管理

于 2021-04-16T21:14:18.253 回答
0
class VisibilityExample extends StatefulWidget {
  const VisibilityExample({Key? key}) : super(key: key);

  @override
  _VisibilityExampleState createState() => _VisibilityExampleState();
}

class _VisibilityExampleState extends State<VisibilityExample> {
  bool visible = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Lines'),
      ),
      body: Container(
        color: Colors.black87,
        child: Stack(alignment: Alignment.bottomCenter, children: [
          ListView(
            shrinkWrap: true,
            children: [
              Container(
                height: 200,
              ),
              InkWell(
                onTap: () {},
                onHover: (value) {
                  print(value);
                  setState(() {
                    visible = !visible;
                  });
                },
                child: Visibility(
                  maintainSize: true,
                  maintainAnimation: true,
                  maintainState: true,
                  visible: visible,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.arrow_left_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.add_circle_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.remove_circle,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.arrow_right_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(Icons.replay_circle_filled_outlined),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ]),
      ),
    );
  }
}
 

在此处输入图像描述

于 2022-01-14T07:56:38.457 回答
-3

也许您可以像这样使用导航器功能Navigator.of(context).pop();

于 2020-07-13T03:18:53.410 回答
-9

一种解决方案是将 tis 小部件颜色属性设置为 Colors.transparent。例如:

IconButton(
    icon: Image.asset("myImage.png",
        color: Colors.transparent,
    ),
    onPressed: () {},
),
于 2018-10-04T13:30:16.390 回答