Показать / скрыть виджеты во Flutter программно


133

В Android каждый Viewподкласс имеет setVisibility()метод, позволяющий изменять видимость Viewобъекта.

Есть 3 варианта настройки видимости:

  • Видимый: визуализирует Viewвидимое внутри макета.
  • Невидимый: скрывает View, но оставляет зазор, эквивалентный тому, Viewчто занимал бы, если бы он был видим
  • Gone: скрывает Viewи полностью удаляет его из макета. Как будто это heightи widthбыло0dp

Есть ли что-то эквивалентное приведенному выше для виджетов во Flutter?

Для быстрой справки: https://developer.android.com/reference/android/view/View.html#attr_android:visibility

Ответы:


90

ОБНОВЛЕНИЕ: поскольку этот ответ был написан, он Visibilityбыл представлен и обеспечивает лучшее решение этой проблемы.


Вы можете использовать Opacityс opacity:из 0.0рисовать сделать элемент скрыт , но до сих пор занимает пространство.

Чтобы он не занимал места, замените его пустым Container().

РЕДАКТИРОВАТЬ: чтобы обернуть его в объект непрозрачности, выполните следующие действия:

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

Краткое руководство по непрозрачности для разработчиков Google: https://youtu.be/9hltevOHQBw


3
Спасибо! Да, это не самый чистый способ сделать это, но он определенно поможет. Есть ли шанс интегрировать функцию видимости с виджетами в будущем?
user3217522

4
Если виджет обычно реагирует на ввод пользователя, не забудьте также заключить его в IgnorePointerоболочку, иначе пользователь все равно может запустить его.
Дункан Джонс

1
Это не идеально, поскольку виджет все еще существует и может реагировать на нажатия и т. Д. См. Ответ ниже, используя виджет видимости, чтобы лучше справиться с этим.
Рассел Зорнес

Как говорится в комментариях вверху, использование непрозрачности приведет к рендерингу виджета в дереве renderTree, что в некоторых случаях не то, что вам нужно. Рекомендуется использовать виджет видимости.
Исак Моура,

Сделать виджет невидимым и иметь прозрачность as0 - это разные вещи. С невидимым виджетом вы все еще можете взаимодействовать с ним, он просто невидим. Виджет видимости позволяет удалять виджет, пока он не понадобится.
UndercoverCoder

193

Невидимый : виджет занимает физическое пространство на экране, но не виден пользователю.

Gone : виджет не занимает никакого физического места и полностью исчез.


Невидимый пример

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

Ушедший пример

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

В качестве альтернативы вы можете использовать ifусловие как для невидимого, так и для исчезнувшего.

Column(
  children: <Widget>[
    if (show) Text("This can be visible/not depending on condition"),
    Text("This is always visible"),
  ],
) 

20
Это условие «если» идеально!
johnc

как использовать здесь еще условие?
Быстрый ученик

@Quicklearner Можно использоватьif(show) Text('Showing) else Text('Not showing)
CopsOnRoad

63

Для сотрудничества с вопросом и показать пример замены его пустым 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],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
            ],
          )                    
        ],
      )
    );
  }
}

5
Это должен быть принятый ответ. Это правильная реализация «программно отображать / скрывать виджеты»
Бишваджиоти Рой

Да, это определенно должно быть принято, потому что здесь используется фундамент Flutter, то есть setState () ... иначе как еще вы собираетесь перемещаться между Visible / InVisible в своем виджете Stateful!?.
Yo Apps

29

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

21

Попробуйте Offstageвиджет

если атрибут offstage:trueне занимает физическое пространство и невидим,

если атрибут, offstage:falseон будет занимать физическое пространство и быть видимым

Offstage(
   offstage: true,
   child: Text("Visible"),
),

Обратите внимание на это: в документации Flutter указано: «Offstage можно использовать для измерения размеров виджета, не выводя его на экран (пока). Чтобы скрыть виджет из поля зрения, пока он не нужен, предпочтите полностью удалить виджет из дерева. вместо того, чтобы сохранять его в поддереве за сценой. ".
Лукеич

13

Вы можете инкапсулировать любой виджет в своем коде с помощью нового виджета под названием (Видимость), это от желтой лампы в самой левой части виджета, которая должна быть невидимой.

пример: скажем, вы хотите сделать строку невидимой:

  1. Щелкните лампу и выберите (Обернуть с виджетом)
  2. Переименуйте виджет в Видимость
  3. Добавьте свойство visible и установите для него значение false
  4. Дочерний элемент вновь созданного виджета (виджет видимости) - это виджет, который вы хотите, чтобы он был невидимым.

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

Надеюсь, это поможет кому-то в будущем


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

9

В Flutter 1.5 и Dart 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; 
                  });
              },)

          ],
        )

Это намного лучше, чем варианты, доступные в предыдущей версии flutter / dart. Спасибо!
Hammer

5

Для новичков тоже попробуйте.

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

5

Обновить

У 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. Статья о том, как сделать виджет видимости.

3

Как уже отмечалось @CopsOnRoad, вы можете использовать виджет Visibility. Но если вы хотите сохранить его состояние, например, если вы хотите создать пейджер и заставить определенную кнопку появляться и исчезать в зависимости от страницы, вы можете сделать это следующим образом.

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"
            )
          ],
        ),
      )
    ]))


-8

Одно из решений - установить для этого свойства цвета виджета значение Colors.transparent. Например:

IconButton(
    icon: Image.asset("myImage.png",
        color: Colors.transparent,
    ),
    onPressed: () {},
),

1
Не очень хорошее решение, потому что прозрачный по- IconButtonпрежнему получает щелчок и занимает место. Пожалуйста, отредактируйте или удалите этот ответ, прежде чем люди проголосуют против него.
CopsOnRoad
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.