小菜在學習 Flutter 過程中需要處理一個類似 AndroidPopupWindow 效果的分享彈框頁。看似很簡單的頁面,里面卻有很多值得嘗試的地方。

      小菜測試時主要用 GridViewBottomSheet 來實現的,當然也可以不用 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 小菜理解為是從底部向上彈的工作表,主要分為兩種:

  1. 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: [
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** 不限制寬高,效果為新打開一個頁面,點擊空白區不會消失,如圖:![](https://s4.51cto.com/images/blog/202111/26082356_61a0291cc4a9c62029.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)1.2 若此時設置內容 **Widget** 寬高,會發現依舊是重新打開一個頁面,高度從底向上占據所設置高度,且點擊空白區不會消失,如圖:![](https://s4.51cto.com/images/blog/202111/26082356_61a0291c790bb63327.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)2. **Modal 式工作表**:是一個半透明的頁面,默認占據屏幕一半 **ScaffoldState.showModalBottomSheet**。

@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 _showNomalWid(context);
});
},
child: new Text("我要分享"),
color: Colors.blue);
}),
));
}

2.1 若用 **showModalBottomSheet** 方式開啟工作表,同時內容 **Widget** 不限制寬高,效果為打開一個半透明頁面,默認占據屏幕一半,點擊空白區工作表消失,如圖:![](https://s4.51cto.com/images/blog/202111/26082356_61a0291cc737727330.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)2.2 若此時設置內容 **Widget** 寬高,會發現依舊是打開一個半透明頁面,高度從底向上占據所設置高度,且點擊空白區會消失,如圖:![](https://s4.51cto.com/images/blog/202111/26082356_61a0291ca1ad529082.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)2.3 若此時設置內容 **Widget** 數據量很多,效果如何呢,這就是小菜選擇用 **GridView** 的原因,在現有寬高內進行可滑動操作即可,如圖:![](https://s4.51cto.com/images/blog/202111/26082356_61a0291cbb8a546096.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)#### 核心源碼      小菜稍稍修飾了一下頁面效果,主要源碼如下:

import package:flutter/material.dart;

class SharePopup extends StatelessWidget {
List nameItems = [
微信, 朋友圈, QQ, QQ空間, 微博, FaceBook, 郵件, 鏈接
];
List urlItems = [
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: [
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: [
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), ) ), )
],
),
);
}
}

***      小菜剛接觸 **Flutter** 時間不長,還有很多不清楚和不理解的地方,如果有不對的地方還希望多多指教。> 來源:阿策小和尚