QinGang_interested/lib/pages/user/CustomInput.dart

190 lines
5.2 KiB
Dart

import 'package:flutter/material.dart';
class CustomInput {
static Widget buildInput(
TextEditingController? controller, {
String? title,
String? hint,
bool obscure = false,
Widget? suffix,
TextInputType? keyboardType,
FocusNode? focusNode,
FormFieldValidator<String>? validator,
ValueChanged<String>? onChanged,
String? initialValue,
bool labelInline = false,
double? labelWidth,
}) {
return _CustomInputWidget(
externalController: controller,
title: title,
hint: hint,
obscure: obscure,
suffix: suffix,
keyboardType: keyboardType,
focusNode: focusNode,
validator: validator,
onChanged: onChanged,
initialValue: initialValue,
labelInline: labelInline,
labelWidth: labelWidth,
);
}
}
class _CustomInputWidget extends StatefulWidget {
const _CustomInputWidget({
Key? key,
this.externalController,
this.title,
this.hint,
this.obscure = false,
this.suffix,
this.keyboardType,
this.focusNode,
this.validator,
this.onChanged,
this.initialValue,
this.labelInline = false,
this.labelWidth,
}) : super(key: key);
final TextEditingController? externalController;
final String? title;
final String? hint;
final bool obscure;
final Widget? suffix;
final TextInputType? keyboardType;
final FocusNode? focusNode;
final FormFieldValidator<String>? validator;
final ValueChanged<String>? onChanged;
final String? initialValue;
// new
final bool labelInline;
final double? labelWidth;
@override
State<_CustomInputWidget> createState() => _CustomInputWidgetState();
}
class _CustomInputWidgetState extends State<_CustomInputWidget> {
late final TextEditingController _controller;
late final bool _controllerIsExternal;
bool _showClear = false;
@override
void initState() {
super.initState();
_controllerIsExternal = widget.externalController != null;
_controller = widget.externalController ?? TextEditingController(text: widget.initialValue ?? '');
_showClear = _controller.text.isNotEmpty;
_controller.addListener(_onTextChange);
}
void _onTextChange() {
final has = _controller.text.isNotEmpty;
if (has != _showClear) {
setState(() {
_showClear = has;
});
}
if (widget.onChanged != null) widget.onChanged!(_controller.text);
}
@override
void dispose() {
_controller.removeListener(_onTextChange);
if (!_controllerIsExternal) {
_controller.dispose();
}
super.dispose();
}
void _clearText() {
_controller.clear();
// listener will trigger onChanged
}
Widget _buildTextField({EdgeInsetsGeometry? contentPadding}) {
return SizedBox(
height: 40,
child: TextFormField(
controller: _controller,
obscureText: widget.obscure,
keyboardType: widget.keyboardType,
validator: widget.validator,
focusNode: widget.focusNode,
// 保证文字垂直居中
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: widget.hint,
hintStyle: const TextStyle(color: Color(0xFFB6BAC9), fontSize: 16),
suffixIcon: widget.suffix ?? (_showClear
? IconButton(
icon: const Icon(Icons.cancel, size: 20, color: Colors.grey),
onPressed: _clearText,
)
: null),
isDense: true,
contentPadding: contentPadding ?? const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
border: InputBorder.none,
),
style: const TextStyle(color: Colors.black87, fontSize: 16),
),
);
}
@override
Widget build(BuildContext context) {
final hasTitle = (widget.title ?? '').isNotEmpty;
if (widget.labelInline && hasTitle) {
final double labelW = widget.labelWidth ?? 100.0;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: labelW,
child: Text(
widget.title!,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
),
Expanded(
child: Container(
child: _buildTextField(contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10)),
),
),
],
),
const SizedBox(height: 10),
const Divider(height: 0.5, thickness: 1, color: Color(0xFFBDBDBD)),
],
);
}
// 默认竖排(标题在上)
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (hasTitle)
Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Text(
widget.title!,
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
),
_buildTextField(),
const SizedBox(height: 10),
const Divider(height: 0.5, thickness: 1, color: Color(0xFFBDBDBD)),
],
);
}
}