美文网首页FlutterFlutter圈子Flutter
Flutter 类iOS底部弹出框

Flutter 类iOS底部弹出框

作者: calary | 来源:发表于2020-02-15 20:27 被阅读0次

1、前言

Flutter没有提供底部类似iOS的弹出框,或者是有但是我不知道,毕竟Widget太多,这里先上效果图,可以看下是否符合你的要求。
图1是iOS系统的效果,图2是我们实现的效果

图1.png 图2

2、控件介绍

  • showModalBottomSheet
    系统提供的底部弹出窗,这个弹出框默认是有高度的,代码和默认效果如下图
/// 点击事件
void _selectAction() async {
    int index = await showActionSheets();
  }
/// 弹窗
Future<int> showActionSheets()
  {
    return showModalBottomSheet<int>(
        context: context,
        builder: (BuildContext context){
            return Container();
        }
    );
  }
image.png

3、 具体实现

  • 弹出窗底色为透明色,高度自适应
  • 点击空白区域返回null,取消返回0,其他根据自身index返回
  • 我们对效果进行了封装,并开放了一定的可定制性
    创建类custom_action_sheet,代码如下
    image.png
import 'package:flutter/material.dart';

// 弹出底部sheet
Future<int> showCustomBottomSheet({
  @required BuildContext context,
  double radiusSize = 5.0, // 默认圆角为5
  double paddingSize = 10.0, // 默认左右间距为10
  String title  = '', // 标题
  double titleFontSize = 14, // 标题字体大小
  Color titleColor = Colors.red, // 标题默认颜色
  String cancelTitle = '取消',
  double cancelHeight = 45,
  double cancelFontSize = 15,
  Color cancelTextColor = Colors.black,
  List<Widget> children = const <Widget>[],
  })
{
  assert(context != null);
  return showModalBottomSheet<int>(
    context: context,
    backgroundColor: Color(0x00ffffff), // 背景色设置为无色
    elevation: 0, // 透明度
    builder: (BuildContext context) {
      return GestureDetector(
        onTap: (){
          Navigator.pop(context,-1);
        },
        child: Container(
            color: Color(0x00ffffff), // 设置颜色后点击事件才有效
            alignment: Alignment.bottomCenter,
            padding: EdgeInsets.fromLTRB(paddingSize, 0, paddingSize, MediaQuery.of(context).padding.bottom),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                GestureDetector(
                  onTap: (){},
                  child: Container(
                    padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
                    decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius:  (children.length == 0) ? BorderRadius.all(Radius.circular(radiusSize))
                            : BorderRadius.only(topLeft: Radius.circular(radiusSize), topRight: Radius.circular(radiusSize))
                    ),
                    alignment: Alignment.center,
                    constraints: BoxConstraints(
                      minHeight: 45,
                    ),
                    child: Text(title, textAlign: TextAlign.center,style: TextStyle(color: titleColor, fontSize: titleFontSize),
                    ),
                  ),
                ),
                Column(
                  children:children
                ),
                Container(
                  height: 10,
                ),
                GestureDetector(
                  onTap: (){
                    Navigator.pop(context,0);
                  },
                  child: Container(
                    decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.all(Radius.circular(radiusSize))
                    ),
                    alignment: Alignment.center,
                    height: cancelHeight,
                    child: Text(cancelTitle,style: TextStyle(color: cancelTextColor,fontSize: cancelFontSize),),
                  ),
                ),
              ],
            )
        ),
      );
    },
  );
}

/// 添加时候的item
Widget actionItem({
  @required BuildContext context,
  @required int index,
  @required String title,
  Color color = Colors.black,
  Color backgroundColor = Colors.white,
  double radiusSize = 5.0, // 默认圆角为5
  bool isLastOne = false, // 是否为最后一个,最后一个如果有圆角的话需要增加底部圆角
  double height = 45,
  double fontSize = 15,
}){
  assert(context != null);
  assert(title != null);
  assert(index > 0);
  return GestureDetector(
      onTap: (){
        Navigator.pop(context,index);
      },
      child: Column(
        children: <Widget>[
/// 分割线
          Divider(
            height: 0.5,
            color: Color(0xffeeeeee),
          ),
          Container(
            decoration: BoxDecoration(
                color: backgroundColor,
                borderRadius: isLastOne ? BorderRadius.only(bottomLeft: Radius.circular(radiusSize), bottomRight: Radius.circular(radiusSize)) : BorderRadius.all(Radius.circular(0))
            ),
            alignment: Alignment.center,
            height: height,
            child: Text(title,style: TextStyle(color: color, fontSize: fontSize),),
          )
        ],
      )
  );
}

4、具体使用

import 'package:flutter/material.dart';
import '../../widgets/custom_action_sheet.dart';

class BottomSheetDialog extends StatefulWidget {
  @override
  _BottomSheetDialogState createState() => _BottomSheetDialogState();
}

class _BottomSheetDialogState extends State<BottomSheetDialog> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('弹出框'),
      ),
      body: Container(
        child: Center(
          child: FlatButton(
              onPressed: _selectAction,
              child: Text('底部弹窗')
          ),
        ),
      ),
    );
  }


  void _selectAction() async {
    int index1 = await showPayActionSheets(context: context, title: '支付方式');
    print(index1);
  }

/// 具体使用方式
  Future<int> showPayActionSheets({
    @required BuildContext context,
    @required String title,
  })
  {
    return showCustomBottomSheet(
        context: context,
        title: title,
        children: [
          actionItem(context: context, index: 1, title: '微信支付'),
          actionItem(context: context, index: 2, title: '支付宝支付',isLastOne: true),
        ]
    );
  }
}

5、遗留问题

  • 1、item过多会爆越界错误,可以尝试将Column改成ListView
  • 2、其他

相关文章

网友评论

    本文标题:Flutter 类iOS底部弹出框

    本文链接:https://www.haomeiwen.com/subject/amsyfhtx.html