Mostrar / ocultar widgets no Flutter programaticamente

112

No Android, cada Viewsubclasse tem um setVisibility()método que permite modificar a visibilidade de um Viewobjeto

Existem 3 opções para definir a visibilidade:

  • Visível: torna o Viewvisível dentro do layout
  • Invisível: oculta o View, mas deixa uma lacuna que é equivalente ao que o Viewocuparia se fosse visível
  • Desaparecido: oculta o Viewe o remove inteiramente do layout. É como se fosse heighte widthfosse0dp

Existe algo equivalente ao acima para Widgets no Flutter?

Para uma referência rápida: https://developer.android.com/reference/android/view/View.html#attr_android:visibility

user3217522
fonte

Respostas:

81

ATUALIZAÇÃO: Uma vez que esta resposta foi escrita, Visibilityfoi apresentada e fornece a melhor solução para este problema.


Você pode usar Opacitycom um opacity:de 0.0para desenhar para tornar um elemento oculto, mas ainda ocupar espaço.

Para que não ocupe espaço, substitua por um vazio Container().

EDIT: Para envolvê-lo em um objeto Opacity, faça o seguinte:

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

Tutorial rápido do Google Developers sobre Opacity: https://youtu.be/9hltevOHQBw

Collin Jackson
fonte
3
Obrigado! Sim, essa não é a maneira mais limpa de fazer isso, mas com certeza cumprirá o propósito. Alguma chance de ter uma funcionalidade de visibilidade integrada com widgets no futuro?
user3217522
3
Se o widget normalmente reage à entrada do usuário, certifique-se de envolvê-lo em um IgnorePointertambém, caso contrário, o usuário ainda poderá acioná-lo.
Duncan Jones de
1
Isso não é o ideal, pois o widget ainda está lá e pode responder a toques etc. Veja a resposta abaixo usando o widget de visibilidade para a melhor maneira de lidar com isso.
Russell Zornes de
Como dizem os comentários acima, usar opacidade renderizará o widget na árvore de renderização, em alguns casos não é o que você deseja. Usar o widget de visibilidade é mais recomendado.
Isac Moura
Tornar um widget invisível e ter opacidade as0 são duas coisas diferentes. Com um widget invisível, você ainda pode interagir com ele, é apenas invisível. O widget de visibilidade permite que você remova o widget até que seja necessário.
UndercoverCoder
173

Invisível : o widget ocupa espaço físico na tela, mas não fica visível para o usuário.

Desaparecido : o widget não ocupa nenhum espaço físico e desapareceu completamente.


Exemplo invisível

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

Exemplo ido

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

Alternativamente, você pode usar a ifcondição para invisível e desaparecido.

Column(
  children: <Widget>[
    if (show) Text("This can be visible/not depending on condition"),
    Text("This is always visible"),
  ],
) 
CopsOnRoad
fonte
16
Essa condição 'se' é perfeita!
johnc
Eu amo flutter ❤️
nipunasudha
62

Para colaborar com a questão e mostrar um exemplo de substituição por um vazio Container().

Aqui está o exemplo abaixo:

insira a descrição da imagem aqui

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],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
            ],
          )                    
        ],
      )
    );
  }
}
rafaelcb21
fonte
5
Esta deve ser a resposta aceita. Esta é a implementação correta de "mostrar / ocultar widgets programaticamente"
Bishwajyoti Roy
Sim, definitivamente deve ser aceito porque usa um pilar de base do Flutter, ou seja, setState () ... caso contrário, de que outra forma você vai e volta entre Visible / InVisible em seu widget Stateful!?.
Yo Apps
27

Flutter agora contém um widget de visibilidade que você deve usar para mostrar / ocultar widgets. O widget também pode ser usado para alternar entre 2 widgets, alterando a substituição.

Este widget pode atingir qualquer um dos estados visível, invisível, desaparecido e muito mais.

    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
    ),
Edmore M Gonese Digolodollarz
fonte
19

Experimente o Offstagewidget

se o atributo offstage:truenão ocupar o espaço físico e invisível,

se atributo offstage:falsevai ocupar o espaço físico e visível

Offstage(
   offstage: true,
   child: Text("Visible"),
),
Equipe Android
fonte
Observação sobre isso: o estado do Flutter docs , "Offstage pode ser usado para medir as dimensões de um widget sem trazê-lo na tela (ainda). Para ocultar um widget da visualização enquanto ele não é necessário, prefira remover o widget inteiramente da árvore ao invés de mantê-lo vivo em uma subárvore Offstage. ".
lukeic
10
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('');
                  },),
                ),
              ),
            ),
          ),
          ),
Alan john
fonte
9

No flutter 1.5 e no Dart 2.3 para a visibilidade perdida, você pode definir a visibilidade usando uma instrução if dentro da coleção sem ter que fazer uso de contêineres.

por exemplo

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; 
                  });
              },)

          ],
        )
nonybrighto
fonte
Isso é muito melhor do que as opções disponíveis na versão anterior de flutter / dardo. Obrigado!
Hammer
8

Você pode encapsular qualquer widget em seu código com um novo widget chamado (Visibilidade), isto é, a partir da lâmpada amarela no lado esquerdo do widget que você deseja que fique invisível

exemplo: digamos que você queira tornar uma linha invisível:

  1. Clique na lâmpada e escolha (Wrap with widget)
  2. Renomeie o widget para Visibilidade
  3. Adicione a propriedade visible e defina-a como false
  4. O filho do widget recém-criado (widget de visibilidade) é o widget que você deseja que fique invisível

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

Espero que ajude alguém no futuro

Mohammed H. Hannoush
fonte
5

Para iniciantes, tente isso também.

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";
      }
    });
  }
}
Hitesh Danidhariya
fonte
3

Atualizar

Flutter agora tem um widget de visibilidade . Para implementar sua própria solução, comece com o código abaixo.


Faça você mesmo um widget.

aparecer esconder

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);
  }
}

mostrar / remover

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();
  }
}

A propósito, alguém tem um nome melhor para os widgets acima?


Mais leituras

  1. Artigo sobre como fazer um widget de visibilidade.
Amsakanna
fonte
3

Como já destacado por @CopsOnRoad, você pode usar o widget Visibility. Mas, se você quiser manter seu estado, por exemplo, se você quiser construir um viewpager e fazer um certo botão aparecer e desaparecer com base na página, você pode fazer desta forma

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 == true ? true : false,
              child: "your widget"
            )
          ],
        ),
      )
    ]))
AlexPad
fonte
0

Talvez você possa usar a função Navigator assim Navigator.of(context).pop();

Onkar Nirhali
fonte
-8

Uma solução é definir esta propriedade de cor do widget como Colors.transparent. Por exemplo:

IconButton(
    icon: Image.asset("myImage.png",
        color: Colors.transparent,
    ),
    onPressed: () {},
),
Edmond
fonte
1
Não é uma boa solução porque o transparente IconButtonainda recebe cliques e ocupa espaço. Edite ou exclua esta resposta antes que as pessoas votem contra ela.
CopsOnRoad