一、说明
在 Android 开发中,我们如果想隐藏一个控件只需要设置 visibility 属性为 inVisible 和 gone 即可,因为这个是基类 View 自带的属性,所有子 View 都通用。而 Flutter 的开发却不能如此直接,由于 Flutter 本着“一切皆组件”的原则,这类型的设置基本上只能通过组件去设置,下面总结一下隐藏控件的几种方法。
二、具体方法
方法1:Visibility 组件
Widget getWidget() {
return Visibility (
visible: false, // 设置是否可见:true:可见 false:不可见
child: Text('Hello World')
);
}
方法2:OffStage 组件
Widget getWidget() {
return Offstage (
offstage: true, // 设置是否可见:true:不可见 false:可见
child: Text('Hello World')
);
}
方法3:Opacity 组件
Widget getWidget() {
return Opacity (
opacity: 0.0, // 设置是否可见:0:不可见 1:可见
child: Text('Hello World')
);
}
方法4:设置 size
Widget getWidget4() {
return Container (
height: 0.0, // 设置是否可见:0:不可见 指定尺寸:可见
child: Text('Hello World')
);
}
方法5:空组件占位
bool isHideWidget = true;
getWidget() {
return isHideWidget ? Container() : Text('Hello World');
}
1.假如仅仅判断是否显示 且不保留位置 用 Offstage
Offstage(
offstage: 布尔值, 当为true时,将隐藏组件且不保留空间位置
child: 组件,)注意:如果Offstage 和 Positioned 一起使用,要把 Offstage 放Positioned里面,包裹 Positioned 会出现问题2.假如仅仅判断是否显示 且保留位置 用组件Opacity
body: new Center( child: new Opacity( opacity: 0.1, child: new Container( height: 100.0, width: 250.0, color: Colors.red, ), ), )
3. 假如判断两个控件是否显示哪个控件 用 Visibility replacement 属性就是要显示的另一个控件
Visibility( //vip过期 或者数据为空 展示的视图 replacement: brandItemModel == null ? Container() : Container( child: Image.asset( ImgAssets.icon_icon_com, scale: 2.1, ), ), //vip下要展示的视图 visible: !DateUtils.timeVipDiss(brandItemModel?.vipEndtime), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( child: Image.asset( ImgAssets.icon_tip_mxt, scale: 2.1, ), ), SizedBox( width: 5, ), Text("盟信通认证,真实品牌商家", maxLines: 1, overflow: TextOverflow.ellipsis, style: pingFangM(10, color: Color(0xFF666666))), Container( child: Image.asset( ImgAssets.icon_toward_light, scale: 2.5, ), ) ], ), )
三、问题
问题1:Offstage 和 Visibility 有什么区别,分别的应用场景是什么?
其实大多时候感觉区别不是很大,Offstage 提供的属性比较少,感觉是专门用来做简单的显示和隐藏的, Visibility 会提供较多的一些特性:
看完属性介绍有所了解:我们一般的需求用哪个都可以,如果有一些类似“不可见时展示一个默认的组件”等这类型需求,可以用 Visibility 组件实现。
Visibility构造器
const Visibility({
Key key,
@required this.child,
this.replacement = const SizedBox.shrink(), // 不可见时显示的组件,只有maintainState=false才会显示。
this.visible = true, // 是否可见
this.maintainState = false, // 隐藏后是否位置组件状态
this.maintainAnimation = false, // 隐藏后是否维持子组件中的动画
this.maintainSize = false, // 隐藏后所占空间是否释放
this.maintainSemantics = false,
this.maintainInteractivity = false, // 隐藏后是否能够照常响应事件
}) : assert(child != null),
assert(replacement != null),
assert(visible != null),
assert(maintainState != null),
assert(maintainAnimation != null),
assert(maintainSize != null),
assert(maintainState == true || maintainAnimation == false, 'Cannot maintain animations if the state is not also maintained.'),
assert(maintainAnimation == true || maintainSize == false, 'Cannot maintain size if animations are not maintained.'),
assert(maintainSize == true || maintainSemantics == false, 'Cannot maintain semantics if size is not maintained.'),
assert(maintainSize == true || maintainInteractivity == false, 'Cannot maintain interactivity if size is not maintained.'),
super(key: key);
注意:注意Visibility构造其中的断言部分:当maintainState为false时,maintainAnimation必须为false;当maintainAnimation为false时,maintainSize必须为false;当maintainSize为false时,matianInteractivety必须为false。
demo:
import 'package:flutter/material.dart';
class OffstageDemo extends StatefulWidget{
@override
_OffstageDemoState createState() {
// TODO: implement createState
return _OffstageDemoState();
}
}
class _OffstageDemoState extends State<OffstageDemo>{
bool _isShow = false;
bool _visible = true;
bool _saveSpace = false;
bool _isInteractive = false;
@override
Widget build(BuildContext context) {
// TODO: implement build
return SingleChildScrollView(
child: Column(
children: <Widget>[
SwitchListTile(
value: _isShow,
title: Text('Offstage(是否隐藏)'),
onChanged: (val) => setState(() => _isShow = !_isShow),
),
Offstage(
offstage: _isShow,
child: Container(
constraints: BoxConstraints.tight(Size(200.0, 100.0)),
margin: EdgeInsets.symmetric(vertical: 40.0),
color: Colors.blue,
),
),
Container(
constraints: BoxConstraints.tight(Size(200.0, 100.0)),
color: Colors.yellow,
margin: EdgeInsets.only(bottom: 40.0),
),
Divider(),
SwitchListTile(
value: _visible,
title: Text('Visibility(是否可见)'),
onChanged: (val) => setState(() => _visible = val),
),
SwitchListTile(
title: Text('是否占用空间'),
value: _saveSpace,
onChanged: (val) => setState((){
_saveSpace = val;
// ignore: unnecessary_statements
!_saveSpace && (_isInteractive = false);
}),
),
SwitchListTile(
title: Text('隐藏后是否响应事件'),
value: _isInteractive,
onChanged: (val) => setState((){
_isInteractive = val;
// ignore: unnecessary_statements
_isInteractive && (_saveSpace = true);
}),
),
Visibility(
visible: _visible,
maintainState: true,
maintainAnimation: true,
maintainSize: _saveSpace,
maintainInteractivity: _isInteractive,
child: GestureDetector(
child: Container(
constraints: BoxConstraints.tight(Size(200.0, 100.0)),
margin: EdgeInsets.symmetric(vertical: 40.0),
color: Colors.blue,
),
onTap: () {
print('tap');
},
),
),
Container(
constraints: BoxConstraints.tight(Size(200.0, 100.0)),
color: Colors.yellow,
margin: EdgeInsets.only(bottom: 40.0),
),
],
),
);
}
}
运行结果:
在Visibility示例中,当蓝色部分隐藏后,将是否占用空间
及隐藏后是否响应事件
开关激活,这时之前的蓝色Container所拥有的的空间被保留了下来,点击这块空白区域,控制台还可以打印tap
。关闭隐藏后是否响应事件
后,再点击空白区域,控制台将不再打印tap
。