flexi_form_field 2.0.1
flexi_form_field: ^2.0.1 copied to clipboard
A flexible and customizable TextFormField widget for Flutter with built-in validation, formatting, mandatory fields, prefix/suffix icons, and more.
import 'package:flexi_form_field/flexi_form_field.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flexi Form Field Showcase',
theme: ThemeData(
useMaterial3: true,
primaryColor: const Color(0xFF673AB7),
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF673AB7),
primary: const Color(0xFF673AB7),
),
scaffoldBackgroundColor: const Color(0xFFF8F9FA),
),
home: const ExampleScreen(),
);
}
}
class ExampleScreen extends StatefulWidget {
const ExampleScreen({super.key});
@override
State<ExampleScreen> createState() => _ExampleScreenState();
}
class _ExampleScreenState extends State<ExampleScreen> {
int _currentStep = 0;
int _tabIndex = 0;
final Map<String, TextEditingController> _controllers = {
'text': TextEditingController(),
'date': TextEditingController(),
'time': TextEditingController(),
'dateTime': TextEditingController(),
'autoComplete': TextEditingController(),
};
String? _selectedValue;
final FlexiFormTheme _appTheme = const FlexiFormTheme(
primaryColor: Color(0xFF673AB7),
borderRadius: BorderRadius.all(Radius.circular(12)),
fillColor: Color(0xFFF3E5F5),
);
final List<String> _categories = ["Text Inputs", "Date & Time", "Interactive", "Real Form"];
final List<String> _styles = ["Outline", "Filled", "Rounded", "Underline", "Minimal"];
FlexiFieldStyle get _selectedStyle {
switch (_tabIndex) {
case 1:
return FlexiFieldStyle.filled;
case 2:
return FlexiFieldStyle.rounded;
case 3:
return FlexiFieldStyle.underline;
case 4:
return FlexiFieldStyle.minimal;
default:
return FlexiFieldStyle.outline;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Flexi Widgets Showcase",
style: TextStyle(fontWeight: FontWeight.bold),
),
centerTitle: true,
elevation: 0,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: _sectionHeader("Stepper"),
),
FlexiStepper(
currentStep: _currentStep,
stepTitles: _categories,
onStepChange: (index) => setState(() => _currentStep = index),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: _sectionHeader("Tab Bar"),
),
FlexiTabBar(
tabs: _styles,
currentIndex: _tabIndex,
onChanged: (index) => setState(() => _tabIndex = index),
backgroundColor: Colors.grey.shade200,
activeColor: const Color(0xFF673AB7),
fontSize: 12,
borderRadius: BorderRadius.circular(5),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: _buildContent(),
),
),
],
),
),
);
}
Widget _buildContent() {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: ListView(
key: ValueKey("$_currentStep-$_tabIndex"),
physics: const BouncingScrollPhysics(),
children: [
if (_currentStep == 0) ..._buildTextInputs(),
if (_currentStep == 1) ..._buildPickers(),
if (_currentStep == 2) ..._buildInteractive(),
if (_currentStep == 3) _buildRealForm(),
],
),
);
}
List<Widget> _buildTextInputs() {
return [
_sectionHeader("Standard Input"),
FlexiFormField(
controller: _controllers['text']!,
label: "Username",
hint: "Enter your username",
fieldStyle: _selectedStyle,
theme: _appTheme,
isMandatory: true,
),
const SizedBox(height: 20),
_sectionHeader("Selection Dropdown"),
FlexiDropDown(
label: "Department",
value: _selectedValue,
fieldStyle: _selectedStyle,
theme: _appTheme,
items: const [
DropdownMenuItem(value: "IT", child: Text("Information Technology")),
DropdownMenuItem(value: "HR", child: Text("Human Resources")),
DropdownMenuItem(value: "FIN", child: Text("Finance")),
],
onChanged: (val) => setState(() => _selectedValue = val),
),
const SizedBox(height: 20),
_sectionHeader("Auto-Complete Field"),
FlexiAutoComplete<String>(
controller: _controllers['autoComplete']!,
label: "Favorite Fruit",
hint: "Start typing...",
options: const ["Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape", "Honeydew"],
itemLabelBuilder: (item) => item,
onSelected: (val) => debugPrint("Selected: $val"),
fieldStyle: _selectedStyle,
theme: _appTheme,
),
];
}
List<Widget> _buildPickers() {
return [
_sectionHeader("Date Selection"),
FlexiDatePicker(
controller: _controllers['date']!,
label: "Birth Date",
fieldStyle: _selectedStyle,
theme: _appTheme,
isMandatory: true,
),
const SizedBox(height: 20),
_sectionHeader("Time Selection"),
FlexiTimePicker(
controller: _controllers['time']!,
label: "Meeting Time",
fieldStyle: _selectedStyle,
theme: _appTheme,
),
const SizedBox(height: 20),
_sectionHeader("Combined Picker"),
FlexiDateTimePicker(
controller: _controllers['dateTime']!,
label: "Appointment",
fieldStyle: _selectedStyle,
theme: _appTheme,
),
];
}
List<Widget> _buildInteractive() {
return [
_sectionHeader("Flexible Timer"),
const FlexiTimer(),
const SizedBox(height: 30),
_sectionHeader("Custom Buttons"),
Wrap(
spacing: 12,
runSpacing: 12,
alignment: WrapAlignment.center,
children: [
FlexiButton(
width: 140,
color: const Color(0xFF673AB7),
onTap: () {},
child: const Text("Primary", style: TextStyle(color: Colors.white)),
),
FlexiButton(
width: 140,
gradient: const LinearGradient(colors: [Colors.blue, Colors.cyan]),
onTap: () {},
child: const Text("Gradient", style: TextStyle(color: Colors.white)),
),
FlexiButton(
width: 140,
elevation: 2,
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade300),
onTap: () {},
child: const Text("Outlined", style: TextStyle(color: Colors.black)),
),
],
),
];
}
Widget _buildRealForm() {
final formKey = GlobalKey<FormState>();
return Column(
children: [
_sectionHeader("Registration Example"),
Material(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
elevation: 4,
shadowColor: Colors.black12,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Form(
key: formKey,
child: Column(
children: [
FlexiFormField(
label: "Full Name",
prefixIcon: const Icon(Icons.person_outline),
fieldStyle: _selectedStyle,
theme: _appTheme,
isMandatory: true,
),
const SizedBox(height: 16),
FlexiFormField(
label: "Email Address",
prefixIcon: const Icon(Icons.email_outlined),
fieldStyle: _selectedStyle,
theme: _appTheme,
isMandatory: true,
),
const SizedBox(height: 16),
FlexiDatePicker(
controller: TextEditingController(),
label: "Date of Birth",
prefixIcon: const Icon(Icons.calendar_today_outlined),
fieldStyle: _selectedStyle,
theme: _appTheme,
),
const SizedBox(height: 24),
FlexiButton(
height: 50,
width: double.infinity,
gradient: const LinearGradient(colors: [Color(0xFF673AB7), Color(0xFF9575CD)]),
onTap: () {
if (formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Processing Data...")),
);
}
},
child: const Text(
"SIGN UP",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16),
),
),
],
),
),
),
),
],
);
}
Widget _sectionHeader(String title) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
children: [
Container(
width: 4,
height: 20,
decoration: BoxDecoration(
color: const Color(0xFF673AB7),
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 8),
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
],
),
);
}
}