Created
October 10, 2025 17:54
-
-
Save cjamcu/cd72ad0d2b3c611a52eca8a3951c7f89 to your computer and use it in GitHub Desktop.
flutter field
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import 'package:flutter/services.dart'; | |
| // Color constants | |
| class AppColors { | |
| static const Color red300 = Color(0xFFFF727F); | |
| static const Color primary500 = Color(0xFF02FB7E); | |
| static const Color neutral300 = Color(0xFF979797); | |
| static const Color neutral50 = Color(0xFFE3E3E3); | |
| static const Color neutral900 = Color(0xFF191919); | |
| } | |
| // Currency Input Field Widget | |
| class CurrencyInputField extends StatefulWidget { | |
| // Validation parameters | |
| final String? Function(double value)? validator; | |
| // UI parameters | |
| final String currencySymbol; | |
| final String currencyCode; | |
| final String? hintText; | |
| const CurrencyInputField({ | |
| super.key, | |
| this.validator, | |
| this.currencySymbol = '\$', | |
| this.currencyCode = 'CLP', | |
| this.hintText, | |
| }); | |
| @override | |
| _CurrencyInputFieldState createState() => _CurrencyInputFieldState(); | |
| } | |
| class _CurrencyInputFieldState extends State<CurrencyInputField> { | |
| final FocusNode _focusNode = FocusNode(); | |
| String? _errorMessage; | |
| final TextEditingController controller = TextEditingController(); | |
| @override | |
| void initState() { | |
| super.initState(); | |
| controller.addListener(_onControllerChanged); | |
| } | |
| @override | |
| void dispose() { | |
| controller.removeListener(_onControllerChanged); | |
| _focusNode.dispose(); | |
| super.dispose(); | |
| } | |
| void _onControllerChanged() { | |
| setState(() { | |
| _validateValue(); | |
| }); | |
| } | |
| void _validateValue() { | |
| double value = double.parse(controller.text); | |
| _errorMessage = null; | |
| // Check custom validator | |
| if (widget.validator != null) { | |
| _errorMessage = widget.validator!(value); | |
| } | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Container( | |
| color: Colors.transparent, | |
| child: Column( | |
| children: [ | |
| Row( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| crossAxisAlignment: CrossAxisAlignment.center, | |
| children: [ | |
| // Currency symbol | |
| Text( | |
| widget.currencySymbol, | |
| style: TextStyle( | |
| color: _errorMessage != null ? AppColors.red300 : AppColors.neutral50, | |
| fontSize: 48, | |
| fontWeight: FontWeight.w300, | |
| height: 1.2, | |
| ), | |
| ), | |
| SizedBox(width: 12), | |
| // Text field | |
| Flexible( | |
| child: IntrinsicWidth( | |
| child: TextField( | |
| controller: controller, | |
| focusNode: _focusNode, | |
| style: TextStyle( | |
| color: _errorMessage != null ? AppColors.red300 : AppColors.neutral50, | |
| fontSize: 48, | |
| fontWeight: FontWeight.w300, | |
| height: 1.2, | |
| ), | |
| cursorColor: AppColors.primary500, | |
| cursorWidth: 3, | |
| cursorHeight: 48, | |
| decoration: InputDecoration( | |
| hintText: widget.hintText ?? '0', | |
| hintStyle: TextStyle( | |
| color: AppColors.neutral50.withValues(alpha: 0.3), | |
| fontSize: 48, | |
| fontWeight: FontWeight.w300, | |
| height: 1.2, | |
| ), | |
| border: InputBorder.none, | |
| enabledBorder: InputBorder.none, | |
| focusedBorder: InputBorder.none, | |
| errorBorder: InputBorder.none, | |
| focusedErrorBorder: InputBorder.none, | |
| contentPadding: EdgeInsets.zero, | |
| isDense: true, | |
| ), | |
| keyboardType: TextInputType.number, | |
| inputFormatters: [ | |
| FilteringTextInputFormatter.digitsOnly, | |
| LengthLimitingTextInputFormatter(10), // Máximo 9.999.999.999 | |
| ], | |
| textAlign: TextAlign.center, | |
| ), | |
| ), | |
| ), | |
| SizedBox(width: 12), | |
| // Currency code | |
| Text( | |
| widget.currencyCode, | |
| style: TextStyle( | |
| color: AppColors.neutral300, | |
| fontSize: 28, | |
| fontWeight: FontWeight.w400, | |
| height: 1.2, | |
| ), | |
| ), | |
| ], | |
| ), | |
| // Error message | |
| if (_errorMessage != null) | |
| Padding( | |
| padding: const EdgeInsets.only(top: 16), | |
| child: Text( | |
| _errorMessage!, | |
| style: TextStyle( | |
| color: AppColors.red300, | |
| fontSize: 14, | |
| ), | |
| ), | |
| ), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| void main() { | |
| runApp(MyApp()); | |
| } | |
| class MyApp extends StatelessWidget { | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| title: 'Currency Input Demo', | |
| theme: ThemeData.dark().copyWith( | |
| primaryColor: AppColors.primary500, | |
| scaffoldBackgroundColor: AppColors.neutral900, | |
| textSelectionTheme: TextSelectionThemeData( | |
| cursorColor: AppColors.primary500, | |
| selectionColor: AppColors.primary500.withOpacity(0.3), | |
| selectionHandleColor: AppColors.primary500, | |
| ), | |
| ), | |
| home: CurrencyInputScreen(), | |
| debugShowCheckedModeBanner: false, | |
| ); | |
| } | |
| } | |
| class CurrencyInputScreen extends StatefulWidget { | |
| @override | |
| _CurrencyInputScreenState createState() => _CurrencyInputScreenState(); | |
| } | |
| class _CurrencyInputScreenState extends State<CurrencyInputScreen> { | |
| @override | |
| void dispose() { | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| backgroundColor: AppColors.neutral900, | |
| body: SafeArea( | |
| child: Padding( | |
| padding: const EdgeInsets.all(24.0), | |
| child: Column( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| children: [ | |
| // Título | |
| Text( | |
| 'Ingresa el monto en pesos', | |
| style: TextStyle( | |
| color: AppColors.neutral50, | |
| fontSize: 20, | |
| fontWeight: FontWeight.w400, | |
| ), | |
| ), | |
| SizedBox(height: 40), | |
| // Input de moneda reutilizable | |
| CurrencyInputField( | |
| validator: (value) { | |
| if (value > 0 && value < 3000) { | |
| return 'El monto mínimo a depositar es \$ 3.000'; | |
| } | |
| if (value > 1000000) { | |
| return 'El monto máximo permitido es \$ 1.000.000'; | |
| } | |
| return null; | |
| }, | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment