【原創不易,轉載請註明出處:https://blog.csdn.net/email_jade/article/details/87922051】
本文起因是由於一個彈窗,要實現一個能夠通過點擊顯示隱藏的功能,效果如下:
第一選擇是採用原生的PopupMenuItem,但是本應用的需求比較特殊,彈出的item自帶背景圖片,並且圖片上面附件了一個Text的文本,item個數恆定爲1個。採用PopupMenuItem會給彈出的item附加一個背景色,默認是跟Theme的cardColor顏色,導致圖片周圍有顏色,並且點擊的時候也會有顏色,看起來體驗極差,放棄該方案。
第二選擇是採用一個隱藏的widget,當點擊的時候展示,然後點擊其他地方的時候隱藏,這個方案是可行的,但是由於該頁面有很多點擊事件,如果每個事件做處理比較麻煩。
第三種方案是模擬原生的PopupMenuItem的控件,自定義子控件。於是閱讀源代碼,發現了PopupRoute,這是一個可以彈出透明的佈局的抽象Route,因此需要自定義一個PopRoute,代碼如下:
class PopRoute extends PopupRoute{
final Duration _duration = Duration(milliseconds: 300);
Widget child;
PopRoute({@required this.child});
@override
Color get barrierColor => null;
@override
bool get barrierDismissible => true;
@override
String get barrierLabel => null;
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return child;
}
@override
Duration get transitionDuration => _duration;
}
需要注意的是transitionDuration不能返回null,否則會報錯。
這個Route是爲了點擊按鈕的時候彈出一個新的頁面,這個新頁面除了自己定義的child,其他全是透明,來看看新的頁面的代碼:
class Popup extends StatelessWidget{
final Widget child;
final Function onClick; //點擊child事件
final double left; //距離左邊位置
final double top; //距離上面位置
Popup({
@required this.child,
this.onClick,
this.left,
this.top,
});
@override
Widget build(BuildContext context) {
return Material(color: Colors.transparent, child: GestureDetector(child: Stack(
children: <Widget>[
Container(width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, color: Colors.transparent,),
Positioned(child: GestureDetector(child: child, onTap: (){ //點擊子child
if(onClick != null){
Navigator.of(context).pop();
onClick();
}
}),
left: left,
top: top,),
],
),
onTap: (){ //點擊空白處
Navigator.of(context).pop();
},
),);
}
}
以上代碼就是用來展示的popup的代碼了。
來看看是怎麼使用的:
///構建用戶頭像按鈕
///點擊頭像彈出退出按鈕
Widget _buildUserIcon() {
return Padding(
padding: EdgeInsets.fromLTRB(20, 22, 0, 0),
child: GestureDetector(
child: Container(
child: Image.asset(
"assets/images/icon_user.png",
),
width: 32,
height: 32,
alignment: AlignmentDirectional.bottomStart),
onTap: _showExit,
),
);
}
///構建退出按鈕
Widget _buildExit() {
return Container(
width: 91,
height: 36,
child: Stack(
children: <Widget>[
Image.asset(
"assets/images/exit.png",
fit: BoxFit.fill,
),
Center(
child: Text(
ProjectLocalizations.of(context).exit,
style: TextStyle(fontSize: 14, color: Colors.black),
),
),
],
),
);
}
///彈出退出按鈕
///點擊退出調用onClick
void _showExit() {
Navigator.push(context, PopRoute(child: Popup(
child: _buildExit(),
left: 64,
top: 22,
onClick: (){
print("exit");
},
),),);
}
使用起來也很方便,直接用Navigator的push方法即可,需要注意的是可以通過left和top計算出來新頁面item的展示位置,可以通過onClick監聽item的點擊事件。
以上就是自定義PopupWindow的全部內容了,代碼比較少,並且全部貼在博客中了,就不貼GitHub地址了。
flutter很好,路還很長,讓我們一起奮鬥前行!