130 lines
4.0 KiB
Dart
130 lines
4.0 KiB
Dart
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter/services.dart';
|
||
|
import 'package:sk_base_mobile/app_theme.dart';
|
||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||
|
|
||
|
class SkNumberInput<T> extends StatefulWidget {
|
||
|
final TextEditingController textController;
|
||
|
final Function(FocusNode)? onTap;
|
||
|
final Function(String)? onChanged;
|
||
|
final void Function(dynamic)? onTapOutside;
|
||
|
final Function(dynamic)? validator;
|
||
|
|
||
|
final bool isDense;
|
||
|
final EdgeInsetsGeometry? contentPadding;
|
||
|
final bool autoFocus;
|
||
|
final bool isRequired;
|
||
|
final String labelText;
|
||
|
final String? hint;
|
||
|
final ValueChanged<T>? onFieldSubmitted;
|
||
|
const SkNumberInput(
|
||
|
{super.key,
|
||
|
required this.textController,
|
||
|
this.onTap,
|
||
|
this.onChanged,
|
||
|
this.hint,
|
||
|
this.onTapOutside,
|
||
|
this.isRequired = false,
|
||
|
this.labelText = '',
|
||
|
this.onFieldSubmitted,
|
||
|
this.autoFocus = false,
|
||
|
this.contentPadding,
|
||
|
this.isDense = false,
|
||
|
this.validator});
|
||
|
|
||
|
@override
|
||
|
State<SkNumberInput> createState() => _SkNumberInputState<T>();
|
||
|
}
|
||
|
|
||
|
class _SkNumberInputState<T> extends State<SkNumberInput> {
|
||
|
late FocusNode focusNode = FocusNode();
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
if (widget.autoFocus) {
|
||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
|
focusNode.requestFocus();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return TextFormField(
|
||
|
focusNode: focusNode,
|
||
|
onTap: () {
|
||
|
if (widget.onTap != null) {
|
||
|
widget.onTap!(focusNode);
|
||
|
}
|
||
|
},
|
||
|
controller: widget.textController,
|
||
|
onFieldSubmitted: (event) {
|
||
|
if (widget.onTapOutside != null) {
|
||
|
dynamic value;
|
||
|
if (T == double) {
|
||
|
value = double.tryParse(widget.textController.text);
|
||
|
|
||
|
widget.onTapOutside!(value as T);
|
||
|
} else {
|
||
|
value = int.tryParse(widget.textController.text);
|
||
|
}
|
||
|
if (widget.validator != null && !widget.validator!(value)) {
|
||
|
return;
|
||
|
}
|
||
|
widget.onTapOutside!(value as T);
|
||
|
}
|
||
|
},
|
||
|
onTapOutside: (event) {
|
||
|
if (widget.onTapOutside != null) {
|
||
|
dynamic value = widget.textController.text;
|
||
|
if (T == double) {
|
||
|
value = double.tryParse(widget.textController.text) ?? 0.0;
|
||
|
|
||
|
widget.onTapOutside!(value as T);
|
||
|
} else {
|
||
|
value = int.tryParse(widget.textController.text) ?? 0;
|
||
|
}
|
||
|
if (widget.validator != null && !widget.validator!(value)) {
|
||
|
return;
|
||
|
}
|
||
|
widget.onTapOutside!(value as T);
|
||
|
FocusScope.of(context).unfocus();
|
||
|
}
|
||
|
},
|
||
|
onChanged: widget.onChanged ?? (_) {},
|
||
|
textAlign: TextAlign.center,
|
||
|
keyboardType: TextInputType.number,
|
||
|
inputFormatters: <TextInputFormatter>[
|
||
|
// 限制输入内容只能是数字和小数点不限制位数
|
||
|
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,10}')),
|
||
|
],
|
||
|
decoration: InputDecoration(
|
||
|
contentPadding: widget.contentPadding,
|
||
|
isDense: widget.isDense,
|
||
|
// contentPadding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(18)),
|
||
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||
|
label: Row(
|
||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||
|
mainAxisSize: MainAxisSize.min,
|
||
|
children: [
|
||
|
if (widget.isRequired)
|
||
|
Text(
|
||
|
"*",
|
||
|
style: TextStyle(
|
||
|
color: Colors.red, fontSize: ScreenAdaper.height(30)),
|
||
|
),
|
||
|
Text(
|
||
|
widget.labelText,
|
||
|
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||
|
),
|
||
|
]),
|
||
|
focusedBorder: OutlineInputBorder(
|
||
|
borderSide:
|
||
|
const BorderSide(color: AppTheme.primaryColorLight, width: 2),
|
||
|
borderRadius: BorderRadius.circular(ScreenAdaper.sp(15))),
|
||
|
hintText: widget.hint ?? '请输入',
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|