import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'alert_dialog.dart'; /// 小弹窗输入 class VDialogNumber extends StatefulWidget { /// 标题 final String? title; /// 描述 final String? description; /// 输入占位符 final String? placeholder; /// 初始值 final String? initialValue; const VDialogNumber({ Key? key, this.title, this.description, this.placeholder, this.initialValue, }) : super(key: key); @override State createState() => _VDialogNumberState(); Future show() => VAlertDialog.showDialog(this); } class _VDialogNumberState extends State { late TextEditingController _controller; double _value = 0; @override void initState() { super.initState(); _controller = TextEditingController(text: widget.initialValue); _value = double.tryParse(_controller.text) ?? 0; } @override Widget build(BuildContext context) { return VAlertDialog( title: widget.title, width: 440, contentPadding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), content: _buildContent(context), showCancel: true, onConfirm: () { Get.back(result: _controller.text); }, ); } Widget _buildContent(BuildContext context) { final children = []; if (widget.description != null) { children.add( Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: Text( widget.description!, style: const TextStyle(color: Colors.black87, fontSize: 18), ), ), ); children.add(const SizedBox(height: 8)); } else { children.add(const SizedBox(height: 12)); } children.add(_buildInputWidget(context)); return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: children, ), ); } Widget _buildInputWidget(BuildContext context) { const fontSize = 20.0; const height = 56.0; return SizedBox( height: height, child: Row( children: [ IconButton( icon: Icon( Icons.remove, color: _value == 0 ? Colors.grey : Theme.of(context).primaryColor, ), onPressed: _value == 0 ? null : () { setState(() { _value = (_value - 1).clamp(0, 999); // 减1,并限制在0到999之间 _controller.text = _value.toString(); _moveCursorToEnd(); }); }, ), Expanded( child: TextField( controller: _controller, readOnly: false, textAlign: TextAlign.center, autofocus: true, keyboardType: const TextInputType.numberWithOptions( decimal: true), // 允许输入数字和小数点 inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'^\d+\.?\d{0,2}'), ), // 只允许输入数字和小数点,俩位小数 ], style: const TextStyle(fontSize: fontSize), decoration: InputDecoration( border: const UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide(), ), enabledBorder: const UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Colors.black54, ), ), focusedBorder: UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Theme.of(context).primaryColor.withOpacity(.4), ), ), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric( vertical: (height - fontSize * 1.2) / 2, horizontal: 8, ), hintStyle: const TextStyle(fontSize: fontSize), labelStyle: const TextStyle(fontSize: fontSize), hintText: widget.placeholder, isCollapsed: true, ), onChanged: (value) { setState(() { _value = double.tryParse(value) ?? 0; // 将_value的类型改为double }); }, onSubmitted: (value) { Get.back(result: value); }, ), ), IconButton( icon: Icon( Icons.add, color: _value == 999 ? Colors.grey : Theme.of(context).primaryColor, ), onPressed: _value == 999 ? null : () { setState(() { _value = (_value + 1).clamp(0, 999); // 加1,并限制在0到999之间 _controller.text = _value.toString(); _moveCursorToEnd(); }); }, ), ], ), ); } void _moveCursorToEnd() { final text = _controller.text; _controller.value = _controller.value.copyWith( selection: TextSelection.collapsed(offset: text.length), ); } }