小菜在学习 Flutter 过程中需要处理一个类似 Android 中 PopupWindow 效果的分享弹框页。看似很简单的页面,里面却有很多值得尝试的地方。
小菜测试时主要用 GridView 和 BottomSheet 来实现的,当然也可以不用 GridView,小菜简单介绍一下这两组 Widget。
GridView
GridView 我们都很熟悉了,是日常中最常用到的控件之一,小菜前段时间学习了一下 ListView 的基本用法,GridView 的用法基本相同,小菜不再多说,只提醒一个属性,用来设置 GridView item 基本属性。
const SliverGridDelegateWithFixedCrossAxisCount({ @required this.crossAxisCount, // 每行 item 个数 this.mainAxisSpacing = 0.0, // 列间距,即 item 左右间距 this.crossAxisSpacing = 0.0, // 行间距,即 item 上下间距 this.childAspectRatio = 1.0, // item 宽高比,默认1:1})
Tips:注意设置 item 个数与列间距的配合,如果太大可能会造成页面展示不全等异常情况。
BottomSheet
BottomSheet 小菜理解为是从底部向上弹的工作表,主要分为两种:
Persistent 式工作表:类似于一个全新的页面,完全展示 ScaffoldState.showBottomSheet;
@overrideWidget build(BuildContext context) {return new Scaffold( appBar: new AppBar( title: new Text("分享页面"), ), body: new Center( child: new Builder(builder: (BuildContext context) { return new FlatButton( onPressed: () { showBottomSheet( context: context, builder: (BuildContext context) { return _showNomalWid(context); }); }, child: new Text("我要分享"), color: Colors.blue); }), )); }Widget _showNomalWid(BuildContext context) { return new Container(// height: 320.0,// color: Colors.greenAccent, child: new GridView.builder( gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, mainAxisSpacing: 5.0, childAspectRatio: 1.0), itemBuilder: (BuildContext context, int index) { return new Column( children: <Widget>[ new Padding( padding: EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 6.0), child: new Image.asset( 'images/${urlItems[index]}', width: 50.0, height: 50.0, fit: BoxFit.fill, ), ), new Text(nameItems[index]) ], ); }, itemCount: nameItems.length, ), ); }
1.1 若用 showBottomSheet 方式开启工作表,同时内容 Widget 不限制宽高,效果为新打开一个页面,点击空白区不会消失,如图:
1.2 若此时设置内容 Widget 宽高,会发现依旧是重新打开一个页面,高度从底向上占据所设置高度,且点击空白区不会消失,如图:
Modal 式工作表:是一个半透明的页面,默认占据屏幕一半 ScaffoldState.showModalBottomSheet。
@overrideWidget build(BuildContext context) {return new Scaffold( appBar: new AppBar( title: new Text("分享页面"), ), body: new Center( child: new Builder(builder: (BuildContext context) { return new FlatButton( onPressed: () { showModalBottomSheet( context: context, builder: (BuildContext context) { return _showNomalWid(context); }); }, child: new Text("我要分享"), color: Colors.blue); }), )); }
2.1 若用 showModalBottomSheet 方式开启工作表,同时内容 Widget 不限制宽高,效果为打开一个半透明页面,默认占据屏幕一半,点击空白区工作表消失,如图:
2.2 若此时设置内容 Widget 宽高,会发现依旧是打开一个半透明页面,高度从底向上占据所设置高度,且点击空白区会消失,如图:
2.3 若此时设置内容 Widget 数据量很多,效果如何呢,这就是小菜选择用 GridView 的原因,在现有宽高内进行可滑动操作即可,如图:
核心源码
小菜稍稍修饰了一下页面效果,主要源码如下:
import 'package:flutter/material.dart';class SharePopup extends StatelessWidget { List<String> nameItems = <String>[ '微信', '朋友圈', 'QQ', 'QQ空间', '微博', 'FaceBook', '邮件', '链接' ]; List<String> urlItems = <String>[ 'icon_wechat.png', 'icon_wechat_moments.png', 'icon_qq.png', 'icon_qzone.png', 'icon_sina.png', 'icon_facebook.png', 'icon_email.png', 'icon_copylink.png' ]; @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("分享页面"), ), body: new Center( child: new Builder(builder: (BuildContext context) { return new FlatButton( onPressed: () { showModalBottomSheet( context: context, builder: (BuildContext context) { return _shareWidget(context); }); }, child: new Text("我要分享"), color: Colors.blue); }), )); } Widget _shareWidget(BuildContext context) { return new Container( height: 250.0, child: new Column( children: <Widget>[ new Padding( padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0), child: new Container( height: 190.0, child: new GridView.builder( gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, mainAxisSpacing: 5.0, childAspectRatio: 1.0), itemBuilder: (BuildContext context, int index) { return new Column( children: <Widget>[ new Padding( padding: EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 6.0), child: new Image.asset( 'images/${urlItems[index]}', width: 50.0, height: 50.0, fit: BoxFit.fill, ) ), new Text(nameItems[index]) ], ); }, itemCount: nameItems.length, ), ), ), new Container( height: 0.5, color: Colors.blueGrey, ), new Center( child: new Padding( padding: EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 8.0), child: new Text( '取 消', style: new TextStyle(fontSize: 18.0, color: Colors.blueGrey), ) ), ) ], ), ); } }
作者:阿策神奇