Flutter通用UI之BottomSheet

示例图:

在这里插入图片描述

在这里插入图片描述

功能描述

自定义BottomSheet支持单列(拍照,相册类型)和多列(分享类型)

代码

import 'package:flutter/material.dart';
import 'package:flutter_app/ItemBean.dart';

class SharePopupWindow extends StatelessWidget {
  final List<ItemBean> list; //数据源
  final double windowHeight; //弹框高度
  final double contentHeight; //可滚动高度
  final bool isSingleRow; //是否多列
  final OnItemClickListener callBack; //回调
  static BuildContext mContext;

  SharePopupWindow(
      {@required this.list,
      this.windowHeight,
      this.contentHeight,
      this.isSingleRow,
      this.callBack});

/*创建bottomSheet*/
  static void showBottomSheet(
      BuildContext context,
      List<ItemBean> list,
      OnItemClickListener listener,
      bool isSingleRow,
      double windowHeight,
      double contentHeight) {
    mContext = context;
    showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return Stack(
            children: <Widget>[
              Container(
                height: 30.0,
                width: double.infinity,
                color: Colors.black54,
              ),
              Container(
                height: windowHeight ?? 250,
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(8),
                      topRight: Radius.circular(8),
                    )),
              ),
              SharePopupWindow(
                list: list,
                callBack: listener,
                isSingleRow: isSingleRow,
                windowHeight: windowHeight,
                contentHeight: contentHeight,
              ),
            ],
          );
        });
  }

  closeBottomSheet(BuildContext context) {
    print("关闭");
    Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    return _buildWidget();
  }

  Widget _buildWidget() {
    var _defaultWindowHeight = windowHeight ?? 250.0;
    var _defaultContentHeight = contentHeight ?? 190.0;
    var _isSingleRow = isSingleRow ?? true;
    if (_isSingleRow) {
      return _takePhotoWidget(_defaultWindowHeight, _defaultContentHeight);
    } else {
      return _shareWidget(_defaultWindowHeight, _defaultContentHeight);
    }
  }

/*分享朋友圈布局*/
  Widget _shareWidget(double windowHeight, double contentHeight) {
    return new Container(
      height: windowHeight,
      child: new Column(
        children: <Widget>[
          new Padding(
            padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
            child: new Container(
              height: contentHeight,
              child: new GridView.builder(
                gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 4,
                    mainAxisSpacing: 5.0,
                    childAspectRatio: 1.0),
                itemBuilder: (BuildContext context, int index) {
                  return GestureDetector(
                    onTap: () {
                      callBack.onItemClick(index);
                    },
                    child: new Column(
                      children: <Widget>[
                        new Padding(
                            padding: EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 6.0),
                            child: new Image.asset(
                              '${list[index].icon}',
                              width: 50.0,
                              height: 50.0,
                              fit: BoxFit.fill,
                            )),
                        new Text(list[index].title)
                      ],
                    ),
                  );
                },
                itemCount: list.length,
              ),
            ),
          ),
          new Container(
            height: 0.5,
            color: Color(0xffeaeaea),
          ),
          GestureDetector(
            onTap: () {
              closeBottomSheet(mContext);
            },
            child: 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: Color(0xff636B73)),
                  )),
            ),
          )
        ],
      ),
    );
  }

/*拍照布局*/
  Widget _takePhotoWidget(double windowHeight, double contentHeight) {
    return new Container(
      height: windowHeight,
      child: new Column(
        children: <Widget>[
          Container(
            padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
            height: contentHeight,
            child: new ListView.builder(
              itemBuilder: (BuildContext context, int index) {
                return GestureDetector(
                  onTap: () {
                    callBack.onItemClick(index);
                  },
                  child: Center(
                    child: Column(
                      children: <Widget>[
                        Padding(
                          padding: const EdgeInsets.all(10),
                          child: Text(
                            list[index].title,
                            style: TextStyle(
                              color: Color(0xff636B73),
                              fontSize: 16,
                            ),
                          ),
                        ),
                        Container(
                          padding: EdgeInsets.fromLTRB(30, 10, 30, 10),
                          height: 0.5,
                          color: Color(0xffeaeaea),
                        )
                      ],
                    ),
                  ),
                );
              },
              itemCount: list.length,
            ),
          ),
          new Container(
            height: 10,
            color: Color(0xffeaeaea),
          ),
          GestureDetector(
            onTap: () {
              closeBottomSheet(mContext);
            },
            child: 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: Color(0xff636B73)),
                  )),
            ),
          )
        ],
      ),
    );
  }
}

abstract class OnItemClickListener {
  void onItemClick(int index);
}

class ItemBean {
  String icon;
  String title;
  int index;

  ItemBean({this.icon, this.title, this.index});

  @override
  String toString() {
    return 'ItemBean{icon: $icon, title: $title, index: $index}';
  }
}

代码调用

import 'package:flutter/material.dart';
import 'package:flutter_app/SharePopupWindow.dart';

import 'ItemBean.dart';

class SharePopupRouter extends StatelessWidget implements OnItemClickListener {
  List<String> nameItems = <String>[
    '微信',
    '朋友圈',
    'QQ',
    'QQ空间',
    '微博',
    '微师',
    '微为',
    '微问',
    '微未',
  ];
  List<String> urlItems = <String>[
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
    'images/icon_man.png',
  ];

  List<ItemBean> _buildItemList() {
    var list = List<ItemBean>();
    for (var i = 0; i < 9; i++) {
      var item = ItemBean();
      item.title = nameItems[i];
      item.icon = urlItems[i];
      list.add(item);
    }
    return list;
  }

  @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: () {
                  SharePopupWindow.showBottomSheet(
                      context, _buildItemList(), this, true, null, null);
                },
                child: new Text("我要分享"),
                color: Colors.blue);
          }),
        ));
  }

  @override
  void onItemClick(int index) {
    print(_buildItemList()[index].icon);
    print(_buildItemList()[index].title);
  }
}

重要部分

调用

 SharePopupWindow.showBottomSheet(
                      context, _buildItemList(), this, true, null, null);

点击item回调

 @override
  void onItemClick(int index) {
    print(_buildItemList()[index].icon);
    print(_buildItemList()[index].title);
  }

属性定义

|

属性含义
context上下文
list数据源
listeneritem点击监听
isSingleRow是否是单列
windowHeight框体的高度
contentHeight允许滚动的高度

Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值