Atoms

Input Text

How to use?

You will need controller so initialize it first

final TextEditingController controller = TextEditingController();

Simple Default Input

InputText(label: 'Default', controller: controller),

Enable/ Disable Input Field, by default field is enabled

InputText(
    label: 'Disabled',
    isEnabled: false,
    controller: controller,
),

Validate input

final GlobalKey<FormState> formKey = GlobalKey<FormState>();
return Form(
    key: formKey,
    child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
            InputText(
                label: 'Invalid',
                validator: (value) {
                    if (value!.isEmpty) {
                        return 'Field is empty';
                    }
                    return null;
                },
            ),
            verticalMargin8,
            ElevatedButton(
                onPressed: () => formKey.currentState?.validate(),
                child: const Text('Validate'),
            ),
        ],
    ),
);

Change size of Input field, We have five sizes for inputs

// Available sizes
enum InputSize { extraSmall, small, medium, large, extraLarge }
const InputText(size: InputSize.small, label: 'Small'),
const InputText(size: InputSize.medium, label: 'Medium'),
const InputText(size: InputSize.large, label: 'Large'),

Use Prefix and Suffix icons, Note: we need to pass IconData which can be interpreted by FaIcon. You can check documentation here and you can check which icons are available here.

Prefix icon

const InputText(
    label: 'User Prefix Icon',
    prefixOnTap: () {
        print(content: 'Prefix icon onTap');
    },
    prefixIcon: FontAwesomeIcons.user,
),

Suffix icon

const InputText(
    label: 'User Suffix Icon',
    suffixOnTap: () {
        print(content: 'Suffix icon onTap');
    },
    suffixIcon: FontAwesomeIcons.user,
),

Change icon colors

const InputText(
    label: 'Search',
    prefixIcon: FontAwesomeIcons.user,
    prefixIconColor: AppTheme.colors['primary'],
    suffixIcon: FontAwesomeIcons.magnifyingGlass,
    suffixIconColor: AppTheme.colors['primary'],
),

Use custom padding for text input

const InputText(
    label: 'Search',
    padding: horizontalPadding16 + verticalPadding8,
),

Use custom padding for text input

const InputText(
    label: 'Search',
    padding: horizontalPadding16 + verticalPadding8,
),

Use onChanged function to execute action when value is changed

InputText(
    label: 'Test',
    onChanged: (value) {
        print(value);
    },
),

Change validation mode

const InputText(
    label: 'Test',
    autoValidateMode: AutovalidateMode.always,
),

Change keyboard type for field

const InputText(
    label: 'Test',
    keyboardType: TextInputType.number,
),

You will need to declare FocusNode first.

final FocusNode myFocusNode = FocusNode();

Use focusNode to get focus on Button Tap

InputText(
    label: 'Test',
    focusNode: myFocusNode,
),

Use input formatters to restrcit/ allow special kind of values. You might have to hide TextInput from service.

import 'package:flutter/services.dart' hide TextInput;

InputText(
    label: 'Digits Only',
    keyboardType: TextInputType.number,
    inputFormatters: [FilteringTextInputFormatter.digitsOnly],
),

Use minLines and maxLines to set lines visibility.

InputText(
    label: 'Address',
    minLines: 3,
    maxLines: 3,
),

Use inputTextAlign to align the text in center.

InputText(
    label: 'Text Alignment',
    inputTextAlign: TextAlign.center,
),

Use borderWidth for changing border thickness.

InputText(
    label: 'Border width',
    borderWidth: 2,
),

Use focusedEnabledColor to change color of InputText when it's focused.

InputText(
    label: 'Highlight Border Color on focus',
    focusedBorderColor: Colors.blue,
),

Use enabledBorderColor to change border color when InputText is enabled.

InputText(
    label: 'Border Color',
    enabledBorderColor: Colors.amber,
),

Use inputColor for changing user input text color.

InputText(
    label: 'Change user input color',
    inputColor: Colors.blue,
),

Use labelColor to change label color.

InputText(
    label: 'Label color',
    labelColor: Colors.blue,
),

Source Code

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:team/vaahextendflutter/app_theme.dart';
import 'package:team/vaahextendflutter/helpers/constants.dart';
import 'package:team/vaahextendflutter/helpers/enums.dart';

class InputText extends StatelessWidget {
  final String? label;
  final EdgeInsets padding;
  final double borderRadius;
  final bool isEnabled;
  final InputSize size;
  final TextEditingController? controller;
  final Function(String)? onChanged;
  final String? Function(String?)? validator;
  final AutovalidateMode? autoValidateMode;
  final TextInputType? keyboardType;
  final List<TextInputFormatter>? inputFormatters;
  final IconData? prefixIcon;
  final Color? prefixIconColor;
  final Function()? prefixOnTap;
  final IconData? suffixIcon;
  final Color? suffixIconColor;
  final Function()? suffixOnTap;
  final int? minLines;
  final int? maxLines;
  final TextAlign inputTextAlign;
  final double borderWidth;
  final Color? focusedBorderColor;
  final Color? inputColor;
  final Color? labelColor;
  final Color? enabledBorderColor;

  const InputText({
    super.key,
    this.label,
    this.padding = allPadding12,
    this.borderRadius = defaultPadding / 2,
    this.isEnabled = true,
    this.size = InputSize.medium,
    this.controller,
    this.onChanged,
    this.autoValidateMode,
    this.validator,
    this.keyboardType,
    this.inputFormatters,
    this.prefixIcon,
    this.prefixIconColor,
    this.prefixOnTap,
    this.suffixIcon,
    this.suffixIconColor,
    this.suffixOnTap,
    this.minLines,
    this.maxLines,
    this.inputTextAlign = TextAlign.start,
    this.borderWidth = 1,
    this.focusedBorderColor,
    this.inputColor,
    this.labelColor,
    this.enabledBorderColor,
  });

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      textAlign: inputTextAlign,
      decoration: InputDecoration(
        contentPadding: padding,
        border: border(AppTheme.colors['black']!.shade400),
        enabledBorder: border(enabledBorderColor ?? AppTheme.colors['black']!.shade400),
        disabledBorder: border(AppTheme.colors['black']!.shade300),
        focusedBorder: border(focusedBorderColor ?? AppTheme.colors['black']!.shade400),
        errorBorder: border(AppTheme.colors['danger']!.shade400),
        focusedErrorBorder: border(AppTheme.colors['danger']!.shade400),
        errorStyle: TextStyle(color: AppTheme.colors['danger']!.shade400),
        hintText: label,
        hintStyle: TextStyle(
          fontSize: getFontSize(),
          color:
              isEnabled ? labelColor : AppTheme.colors['black']!.shade400 : AppTheme.colors['black']!.shade300,
        ),
        prefixIcon: prefixIcon != null
            ? InkWell(
                onTap: prefixOnTap,
                child: Center(
                  child: Container(
                    margin: horizontalPadding4,
                    child: FaIcon(
                      prefixIcon,
                      size: getFontSize() * 1.15,
                      color: prefixIconColor ?? AppTheme.colors['black']!.shade400,
                    ),
                  ),
                ),
              )
            : null,
        prefixIconConstraints: BoxConstraints(
          maxWidth: getFontSize() * 2.3,
          maxHeight: getFontSize() * 2.3,
        ),
        suffixIcon: suffixIcon != null
            ? InkWell(
                onTap: suffixOnTap,
                child: Center(
                  child: Container(
                    margin: horizontalPadding4,
                    child: FaIcon(
                      suffixIcon,
                      size: getFontSize() * 1.15,
                      color: suffixIconColor ?? AppTheme.colors['black']!.shade400,
                    ),
                  ),
                ),
              )
            : null,
        suffixIconConstraints: BoxConstraints(
          maxWidth: getFontSize() * 2.3,
          maxHeight: getFontSize() * 2.3,
        ),
      ),
      keyboardType: keyboardType,
      inputFormatters: inputFormatters,
      validator: validator,
      controller: controller,
      onChanged: onChanged,
      style: TextStyle(
        fontSize: getFontSize(),
        color: isEnabled ? inputColor : AppTheme.colors['black']!.shade400,
      ),
      enabled: isEnabled,
      autovalidateMode: autoValidateMode,
      minLines: minLines,
      maxLines: maxLines,
      focusNode: focusNode,
    );
  }

  OutlineInputBorder border(Color color) {
    return OutlineInputBorder(
      borderRadius: BorderRadius.circular(borderRadius),
      borderSide: BorderSide(
        width: borderWidth,
        color: color,
      ),
    );
  }

  double getFontSize() {
    switch (size) {
      case InputSize.extraSmall:
        return AppTheme.extraSmall;
      case InputSize.small:
        return AppTheme.small;
      case InputSize.large:
        return AppTheme.large;
      case InputSize.extraLarge:
        return AppTheme.extraLarge;
      default:
        return AppTheme.medium;
    }
  }
}

enum InputBorderType {
  underline,
  outline,
  none,
}

Copyright © 2024