Flutter自定义控件之_自定义弹框

在Flutter应用开发中,经常会遇到自定义弹框的开发需求,如下图所示。
在这里插入图片描述
对于这种样式,我们可以选择自定义Dialog,具体的样式可以根据自己的需要进行修改。 例如,下面是我的实现,由于文本是一个列表,所以我需要新建一个实体类,如下所示。

class IntroduceModel {

  int code;
  List<Data> data;

  IntroduceModel({this.code, this.data});

  IntroduceModel.fromJson(Map<String, dynamic> json) {
    code = json['code'];
    if (json['data'] != null) {
      data = new List<Data>();
      json['data'].forEach((v) {
        data.add(new Data.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['code'] = this.code;
    if (this.data != null) {
      data['data'] = this.data.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Data {
  String itemTitle;
  String itemContent;

  Data({this.itemTitle, this.itemContent});

  Data.fromJson(Map<String, dynamic> json) {
    itemTitle = json['itemTitle'];
    itemContent = json['itemContent'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['itemTitle'] = this.itemTitle;
    data['itemContent'] = this.itemContent;
    return data;
  }
}

然后,我们自定义一个Dialog,源码如下:

class IntroduceDialog extends Dialog {
  
  String des='注:以上的单⽇⽬标额从实际年⽬标额、⽉⽬标额取平均值计算⽽来。';
  String title;
  String content;
  bool isForce;
  IntroduceModel model;
  IntroduceDialog({this.title, this.content,this.isForce}){
    if(content!=null){
      model=IntroduceModel.fromJson(json.decode(content));
    }
  }


  @override
   build(BuildContext context) {
    return Material(
      type: MaterialType.transparency,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _buildContent(context),
            _buildClose(context)
          ],
        ),
      ),
    );
  }

  _buildContent(BuildContext context) {
    double sWidth= MediaQuery.of(context).size.width;
    return Container(
      color: Colors.white,
      width: sWidth*0.85,
      height: 420,
      padding: EdgeInsets.only(left: 15,right: 15,top: 10,bottom: 10),
      child: SingleChildScrollView(
        child: Column(
          children: [
            Text(title, style: TextStyle(fontSize: 20,color:Colors.black,fontWeight: FontWeight.bold)),
            SizedBox(height: 5),
            _buildListView(),
            Text(des, style: TextStyle(fontSize: 14)),
          ],
        ),
      ),
    );
  }

  _buildListView() {
    return Container(
      padding: EdgeInsets.only(top: 5,bottom:5,right: 0,),
      child: ListView.separated(
        shrinkWrap: true,
        physics:  NeverScrollableScrollPhysics(),
        itemCount: model.data.length,
        separatorBuilder: (BuildContext context, int index) => Container(
          child:  Divider(),
        ),
        itemBuilder: (context, index) {
          return _buildItem(context,model.data, index);
        },
      ),
    );
  }

  _buildItem(BuildContext context, list, int index) {
    Data item=list[index];
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(item.itemTitle, style: TextStyle(fontSize: 14)),
        Text(item.itemContent, style: TextStyle(fontSize: 14)),
      ],
    );
  }

  _buildClose(BuildContext context) {
    return GestureDetector(
      child: Offstage(
        offstage: isForce,
        child: Container(
            margin: EdgeInsets.only(top: 30),
            child: LoadAssetImage('close_icon', width: 45,height: 45,fit: BoxFit.fill,)
        ),
      ),
      onTap: (){
        Navigator.of(context).pop();
      },
    );
  }


  static showUpdateDialog(BuildContext context, String title,String content, bool isForce) {
    return showDialog(
        barrierDismissible: false,
        context: context,
        builder: (BuildContext context) {
          return WillPopScope(
              child: IntroduceDialog(title: title,content: content, isForce: isForce),onWillPop: _onWillPop);
        });
  }

  static Future<bool> _onWillPop() async{
    return false;
  }


}

需要说的是,自定义的Dialog的根组件需要使用Material,不然的话,Dialog界面的文字下面会出现黄色的下划线,导致这种情况发生的原因是因为,Text widget 隶属于Material 风格下的组件,如果根节点不是Material 相关组件,则会使用默认带黄色下划线的格式。如果根节点是Material 容器组件,则会采用其Material风格的样式(即不带有下换线),解决的方法有三个:

解决方案主要有三种:
1,采用根节点为脚手架Scaffold组件:

Scaffold(body: content,);

2, 采用根节点为Material 组件。

Material(child: content);

3, 逐个修改Text 组件的style 下的decoration为TextDecoration.none。

child: Text(
                      "专栏的文章",
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(
                        decoration: TextDecoration.none,
                        color: Color(0xFF888888),
                        fontSize: 14,
                        fontWeight: FontWeight.bold,
                        fontFamily: defaultFontFamily,
                      ),
                    )

对于间距,只需要使用Offstage组件即可。最后,在需要使用的地方调用一下这个组件即可,如下所示。

 showIntroduceDialog(BuildContext context) async {
    var localData=await rootBundle.loadString('assets/flow_advertis_funnel.json');
    IntroduceDialog.showUpdateDialog(context, '数据说明', localData, false);
  }

感谢阅读

博主在此给大家安利一款分享学习资料的app,此app的主要就是收集了互联网上的各种学习资料做整合并免费分享。里面涵盖了Android、java、python、数据结构、算法、前端、爬虫、大数据、深度学习、UI等等技术,包含M课网课程、某课堂VIP课程、各培训机构课程、某鱼的一些付费课程以及算法面试资料,并且正在不断更新中,你想要的学习资料几乎都有,当然你也可以加入我们的技术Q群获取资料:687667883,任何课程问题可直接咨询群主。
目前对接的课程论坛如下,您可以提前了解下有哪些课程:
链接资源如下:
    享学app资源对接论坛一(IT码上发)
    享学app资源对接论坛二(学途无忧)
download地址如下:
下载二维码_1.0.0版本.png

Flutter是一种跨平台的移动应用程序开发架,它可以让开发者使用Dart语言编写高性能、高保真的应用程序。而cool_ui则是一个开源的Flutter组件库,它提供了一系列的高质量UI组件,包括自定义键盘等。 在cool_ui中,自定义键盘组件提供了一种自定义输入的方式。你可以使用它来创建一个具有不同样式和功能的键盘,以满足你的需求。在使用自定义键盘之前,你需要在你的项目中引入cool_ui库,并在需要使用自定义键盘的页面中导入相关组件。 在cool_ui中,自定义键盘组件分为两种类型:数字键盘和普通键盘。数字键盘通常用于输入数字,而普通键盘则用于输入文本。你可以根据你的需求选择相应的键盘类型,并根据实际情况进行自定义。 以下是一个简单的示例代码,展示了如何使用cool_ui中的自定义键盘组件: ``` import 'package:flutter/material.dart'; import 'package:cool_ui/cool_ui.dart'; class MyKeyboardDemo extends StatefulWidget { @override _MyKeyboardDemoState createState() => _MyKeyboardDemoState(); } class _MyKeyboardDemoState extends State<MyKeyboardDemo> { TextEditingController _controller = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Custom Keyboard Demo'), ), body: Container( padding: EdgeInsets.all(20), child: Column( children: <Widget>[ TextField( controller: _controller, decoration: InputDecoration( labelText: 'Input Text', border: OutlineInputBorder(), ), keyboardType: TextInputType.number, onTap: () { FocusScope.of(context).requestFocus(FocusNode()); showModalBottomSheet( context: context, builder: (BuildContext context) { return CustomKeyboard( type: KeyboardType.number, onTextInput: (text) { setState(() { _controller.text = _controller.text + text; }); }, onBackspace: () { setState(() { _controller.text = _controller.text .substring(0, _controller.text.length - 1); }); }, ); }, ); }, ), ], ), ), ); } } ``` 该示例代码中,我们首先创建了一个TextField用于接收用户输入,并设置了其keyboardType为number。然后,在用户点击该TextField时,我们调用showModalBottomSheet方法来出一个CustomKeyboard组件。 在CustomKeyboard组件中,我们设置了其type为KeyboardType.number,表示这是一个数字键盘。然后,我们通过onTextInput和onBackspace回调来处理用户输入和删除操作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值