Flutter 日记APP-添加笔记本-常用组件封装

前言

先上效果图: 功能很简单:

  1. 输入标题
  2. 是否开启闹钟
  3. 选择闹钟循环样式
  4. 选择提醒时间
  5. 输入描述
  6. 保存

实现方式

首先实现输入标题,考虑到这个样式在开发中会经常用到,决定将这个封装下,方便后面开发使用。

封装 SSLInputRow.dart

分析:组件需要传入标题、显示样式、可选的输入内容。需要返回点击事件、输入改变事件、输入完成事件。颜色啥的由于是项目中统一定义的颜色管理,这里就没添加可传入参数,可根据需要添加。

定义如下:

kotlin 复制代码
enum SSLInputStyle{
  text,//输入文本
  num,//输入数字
  arrow;//不可输入,可点击选择
}
class SSLInputRow extends StatefulWidget{
  final SSLInputStyle style;//样式
  final String title;//标题
  final String? inputText;//输入信息或子标题
  final ValueChanged<String>? onTextChange;//输入改变
  final ValueChanged<String>? onEditComplete;//输入完成事件
  final int tag;
  final GestureTapCallback? onTap;//arrow 类型点击事件
  const SSLInputRow({
    Key? key,
    this.style = SSLInputStyle.text,
    required this.title,
    this.onTextChange,
    this.callback,
    this.tag = 0,
    this.inputText,
    this.onTap,
    this.onEditComplete,
  }):super(key: key);
}

具体实现:

php 复制代码
class SSLInputRowState extends State <SSLInputRow>{
  TextEditingController? textControl;//输入控制器
  @override
  void initState() {
    // TODO: implement initState
    //根据类型判断是否初始化输入控制器并将数据赋值
    if (widget.style != SSLInputStyle.arrow){
      textControl = TextEditingController();
      if (widget.inputText != null){
        var str = widget.inputText!;
        debugPrint("set default text $str");
        textControl!.text = str;//如果有已输入文本则显示已输入文本
      }
    }
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Padding(
      padding: const EdgeInsets.only(top: 1),
      child: GestureDetector(//点击手势
        child: Container(
          color: sslUI.cellBackColor,
          child: Flex(
            direction: Axis.horizontal,
            children: [
              Expanded(
                  flex: 1,//标题和输入区占比1:1
                  child: Container(
                    alignment: Alignment.centerLeft,
                    padding: const EdgeInsets.only(left: 15),
                    height: 50,
                    child: Text(widget.title, style: TextStyle(color: sslUI.mainText),),
                  )
              ),
              Expanded(
                  flex: widget.style == SSLInputStyle.num ? 1 : 1,
                  child: Container(
                    alignment: Alignment.centerRight,
                    padding: const EdgeInsets.only(right: 0,top: 5,bottom: 5),
                    height: 50,
                    child: showText()
                  )
              ),
              styleChange(),
            ],
          ),
        ),
        //手势点击回调
        onTap: (){
          if (widget.onTap != null){
            widget.onTap!();
          }
        },
      )
    );
  }
  //判断显示类型,区分显示的组件
  Widget showText(){
    if (widget.style == SSLInputStyle.arrow){
      if (widget.inputText != null){
        return Text(widget.inputText!, style: TextStyle(color: sslUI.subText),);
      }else{
        return const Padding(padding: EdgeInsets.zero);
      <img src="}" alt="" width="30%" />
    }else{
      return TextField(
        controller: textControl,
        readOnly: widget.style == SSLInputStyle.arrow ? true : false,
        textAlign: TextAlign.right,
        style: TextStyle(color: sslUI.subText),
        keyboardType: widget.style == SSLInputStyle.num ? const TextInputType.numberWithOptions(signed: false, decimal: true) : TextInputType.text,
        decoration: InputDecoration(
          // labelText: widget.inputText,
          hintText: SSLLocales.l_input_placeholder.tr + widget.title,
          fillColor: sslUI.cellBackColor,
          border: InputBorder.none,
          // border: OutlineInputBorder(
          //   borderSide: BorderSide(color: sslUI.priColor, width: 1),
          // ),
        ),
        //输入变化回调
        onChanged: (v){
          if (widget.onTextChange != null){
            widget.onTextChange!(v);
          }
        },
        //输入完成回调
        onEditingComplete: (){
          if (widget.onEditComplete != null){
            widget.onEditComplete!(textControl!.text);
          }
        },
      );
    }
  }
  根据不同风格决定返回widget
  Widget styleChange(){
    if (widget.style == SSLInputStyle.arrow){
      return Padding(
        padding: const EdgeInsets.only(right: 15),
        child: Icon(Icons.arrow_forward_ios, color: sslUI.iconColor,),
      );
    }else{
      return const Padding(padding: EdgeInsets.only(left: 15),);
    }
  }
  @override
  void dispose() {
  //销毁文本输入控制器
    // TODO: implement dispose
    if (textControl != null){
      textControl!.dispose();
    }
    super.dispose();
  }
}
相关推荐
茶底世界之下20 分钟前
花瓣要更柔和,还是更有反差?用 Awaking 做一次对比度取舍
ios
yuanlaile14 小时前
2026年全新Flutter 跨平台开发全栈学习资料整理
flutter·getx·鸿蒙 next·flutter开发鸿蒙·flutter入门实战·flutter全栈
Anhty19 小时前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_9159090621 小时前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
初雪云1 天前
UniApp 云打包拿到 IPA 后,真正的发布工作才刚开始
ios·自动化·编辑器·产品经理·iphone
Lancker1 天前
没有 Mac 也能上架 iOS:GitHub Actions 全自动构建 + 签名 + TestFlight 送审实录
macos·ios·github
茶底世界之下1 天前
晚霞要多暖?用 Awaking 只改色温做一次取舍
ios
恋猫de小郭1 天前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
第10086个小白1 天前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
酒神dnspup1 天前
多地区网站可用性监控怎么做?DNSPup 从基线到告警的完整实战
运维·ios·云计算·iphone·dns·网络监控