Hiển thị / ẩn tiện ích con trong Flutter theo lập trình


111

Trong Android, mỗi Viewlớp con đều có một setVisibility()phương thức cho phép bạn sửa đổi khả năng hiển thị củaView đối tượng

Có 3 tùy chọn cài đặt chế độ hiển thị:

  • Hiển thị: Hiển Viewthị hiển thị bên trong bố cục
  • Invisible: Ẩn View, nhưng để lại một khoảng trống tương đương với những gì Viewsẽ chiếm nếu nó hiển thị
  • Gone: Ẩn Viewvà xóa hoàn toàn khỏi bố cục. Nó như thể nó heightwidthđã0dp

Có thứ gì đó tương đương với những thứ ở trên cho Widgets trong Flutter không?

Để tham khảo nhanh: https://developer.android.com/reference/android/view/View.html#attr_android:visibility

Câu trả lời:


81

CẬP NHẬT: Vì câu trả lời này đã được viết, Visibilityđã được giới thiệu và cung cấp giải pháp tốt nhất cho vấn đề này.


Bạn có thể sử dụng Opacityvới một opacity:của 0.0để vẽ làm cho một phần tử bị ẩn nhưng vẫn chiếm không gian.

Để làm cho nó không chiếm không gian, hãy thay thế nó bằng một cái trống Container().

CHỈNH SỬA: Để bọc nó trong một đối tượng Opacity, hãy làm như sau:

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

Hướng dẫn nhanh dành cho Nhà phát triển của Google về Độ mờ: https://youtu.be/9hltevOHQBw


3
Cảm ơn bạn! Vâng, đó không phải là cách làm sạch sẽ nhất, nhưng nó chắc chắn sẽ làm đúng mục đích. Bất kỳ cơ hội nào để có chức năng hiển thị được tích hợp với các widget trong tương lai?
user3217522

3
Nếu tiện ích con thường phản ứng với thông tin nhập của người dùng, hãy nhớ bọc nó lại IgnorePointer, nếu không người dùng vẫn có thể kích hoạt nó.
Duncan Jones

1
Điều này không lý tưởng vì tiện ích vẫn ở đó và có thể phản hồi với các lần nhấn, v.v. Xem câu trả lời bên dưới bằng cách sử dụng tiện ích Hiển thị để biết cách tốt nhất để xử lý vấn đề này.
Russell Zornes

Như các nhận xét phía trên cho biết, việc sử dụng độ mờ sẽ hiển thị Widget tại renderTree, trong một số trường hợp, đó không phải là điều bạn muốn. Sử dụng tiện ích hiển thị được khuyến khích nhất.
Isac Moura

Làm cho một widget ẩn và có opacity as0 là hai điều khác nhau. Với một widget vô hình, bạn vẫn có thể tương tác với nó, nó chỉ là vô hình. Tiện ích hiển thị cho phép bạn xóa tiện ích đó cho đến khi cần thiết.
UndercoverCoder

173

Ẩn mặt : Tiện ích chiếm không gian thực trên màn hình nhưng không hiển thị cho người dùng.

Đã biến mất : Tiện ích không chiếm bất kỳ dung lượng thực nào và hoàn toàn biến mất.


Ví dụ vô hình

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

Lấy ví dụ

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

Ngoài ra, bạn có thể sử dụng ifđiều kiện cho cả ẩn và biến.

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

16
Điều kiện 'nếu' đó là hoàn hảo!
johnc

Tôi yêu rung động ❤️
nipunasudha

62

Để cộng tác với câu hỏi và hiển thị ví dụ về việc thay thế câu hỏi đó bằng câu hỏi trống Container().

Đây là ví dụ dưới đây:

nhập mô tả hình ảnh ở đây

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
Đây phải là câu trả lời được chấp nhận. Đây là việc thực hiện đúng đắn về "show / hide widgets lập trình"
Bishwajyoti Roy

Vâng, điều này chắc chắn nên được chấp nhận vì điều này sử dụng một trụ cột nền tảng của Flutter tức là setState () ... nếu không thì làm cách nào khác bạn sẽ chuyển qua lại giữa Visible / InVible trong widget Stateful của mình !?
Ứng dụng Yo

27

Flutter hiện chứa một Tiện ích hiển thị mà bạn nên sử dụng để hiển thị / ẩn các tiện ích. Tiện ích cũng có thể được sử dụng để chuyển đổi giữa 2 tiện ích bằng cách thay thế thay thế.

Widget này có thể đạt được bất kỳ trạng thái nào trong số các trạng thái hiển thị, vô hình, biến mất và hơn thế nữa.

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

19

Thử Offstage tiện ích con

thuộc tính if offstage:true không chiếm không gian vật lý và vô hình,

if thuộc tính offstage:falsenó sẽ chiếm không gian vật lý và hiển thị

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

Lưu ý về điều này: trạng thái tài liệu của Flutter , "Offstage có thể được sử dụng để đo kích thước của tiện ích con mà không cần đưa nó lên màn hình (chưa). Để ẩn tiện ích con khỏi chế độ xem trong khi không cần thiết, bạn nên xóa hoàn toàn tiện ích con khỏi cây chứ không phải giữ nó tồn tại trong một cây con 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('');
                  },),
                ),
              ),
            ),
          ),
          ),

9

Trong Fllick 1.5Dart 2.3 không còn khả năng hiển thị, Bạn có thể đặt khả năng hiển thị bằng cách sử dụng câu lệnh if trong bộ sưu tập mà không cần phải sử dụng các vùng chứa.

ví dụ

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

          ],
        )

Điều đó tốt hơn rất nhiều so với các tùy chọn có sẵn trong phiên bản Flagship / Dart trước. Cảm ơn!
Hammer

8

Bạn có thể đóng gói bất kỳ tiện ích nào trong mã của mình bằng một tiện ích mới có tên là (Khả năng hiển thị), đây là từ đèn màu vàng ở phía bên trái của tiện ích mà bạn muốn nó hiển thị

ví dụ: giả sử bạn muốn ẩn một hàng:

  1. Nhấp vào đèn và chọn (Kết hợp với tiện ích)
  2. Đổi tên tiện ích thành Chế độ hiển thị
  3. Thêm thuộc tính hiển thị và đặt nó thành false
  4. Con của widget mới tạo (Visibility Widget) là Widget mà bạn muốn nó ẩn

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

Tôi hy vọng nó sẽ giúp ai đó trong tương lai


5

Đối với người mới bắt đầu, hãy thử cái này.

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

3

Cập nhật

Flutter hiện có một tiện ích Hiển thị . Để triển khai giải pháp của riêng bạn, hãy bắt đầu với đoạn mã dưới đây.


Tự tạo một widget.

hiện an

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

hiển thị / loại bỏ

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

Nhân tiện, có ai có tên tốt hơn cho các widget ở trên không?


Đọc thêm

  1. Bài viết về cách tạo tiện ích hiển thị.

3

Như đã được đánh dấu bởi @CopsOnRoad, bạn có thể sử dụng tiện ích Hiển thị. Tuy nhiên, nếu bạn muốn giữ nguyên trạng thái của nó, ví dụ: nếu bạn muốn tạo một viewpager và làm cho một nút nhất định xuất hiện và biến mất dựa trên trang, bạn có thể làm theo cách này

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

0

Có thể bạn có thể sử dụng chức năng Navigator như thế này Navigator.of(context).pop();


-8

Một giải pháp là đặt thuộc tính màu của tiện ích tis thành Colors.transparent. Ví dụ:

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

1
Không phải là một giải pháp tốt vì trong suốt IconButtonvẫn nhận được nhấp chuột và chiếm không gian. Vui lòng chỉnh sửa hoặc xóa câu trả lời này trước khi mọi người phản đối nó.
CopsOnRoad,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.