Reputation: 3074
I want to make my flutter project highly manageable, apply clean code and maintain DRY concept strictly. There are a lot of input elements in any flutter project. So I want to make this element as a separate widget so that if I want to change in future then I will change in one place. Here is my approach:
import 'package:flutter/material.dart';
import '../utility/validatation.dart';
class RegistrationPage extends StatefulWidget {
static const String routeName = '/registrationPage';
@override
State<RegistrationPage> createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController nameInput = TextEditingController();
final TextEditingController businessName = TextEditingController();
final TextEditingController productTypeId = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: new Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Container(
height: 70,
margin: EdgeInsets.only(bottom: 50),
child: Image(image: AssetImage('assets/logo.png')),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 30.0),
child: TextInput(inputController: nameInput, label: 'আপনার নাম'),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_register(context);
}
},
child: Text('Next'),
)
]),
),
);
}
void _register(BuildContext context) {}
}
class TextInput extends StatelessWidget {
const TextInput({
Key? key,
required this.inputController,
required this.label,
}) : super(key: key);
final TextEditingController inputController;
final String label;
@override
Widget build(BuildContext context) {
return TextFormField(
controller: inputController,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
prefixIcon: Icon(Icons.phone),
labelText: label,
),
validator: (value) {
return Validation.required(value);
},
);
}
}
But I got this error:
What is wrong in my code? Is there any problem in my approach or should I stop thinking to refactor my code as I do? Please also suggest if there is any smarter way to make code more clean and manageable.
Upvotes: 0
Views: 1566
Reputation: 11
import 'package:flutter/material.dart';
import 'package:qa_lint/core/utils/constants/constants.dart';
Widget customTextFormField(
{IconData? prefixIcon,
required context,
required String? labelText,
TextStyle? labelStyle,
EdgeInsetsGeometry? contentPadding,
required String? Function(String?)? validator,
TextInputType? keyboardType,
required TextInputAction? textInputAction,
ValueChanged<String>? onFieldSubmitted,
bool obscureText = false,
required TextEditingController? controller,
bool isTablet = false,
Widget? suffixIcon}) {
final orientations = MediaQuery.of(context).orientation;
return Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
padding: const EdgeInsets.all(10),
child: OrientationBuilder(
builder: (context, orientation) {
final deviceOrantation = MediaQuery.of(context).orientation;
bool isLandscape = deviceOrantation == Orientation.landscape;
return TextFormField(
style: TextStyle(
fontSize: tabletIs(context)
? isLandscape
? mediaQueryHeight(context) * 0.028
: mediaQueryHeight(context) * 0.022
: mediaQueryHeight(context) * 0.022),
controller: controller,
obscureText: obscureText,
validator: validator,
keyboardType: keyboardType,
textInputAction: textInputAction,
onFieldSubmitted: onFieldSubmitted,
decoration: InputDecoration(
errorStyle: TextStyle(
fontSize: defultFontSize(context),
),
suffixIcon: suffixIcon,
prefixIcon: prefixIcon != null
? Icon(
prefixIcon,
color: Colors.black54,
size: tabletIs(context)
? isLandscape
? mediaQueryHeight(context) * 0.04
: iconSizeTablet(context)
: iconSizeMobile(context),
)
: null,
labelText: labelText,
labelStyle: labelStyles(
fontSize: tabletIs(context)
? (orientations == Orientation.landscape
? tabletLandscapeFontSize(context)
: tabletFontSize(context))
: defultFontSize(context),
),
contentPadding: tabletIs(context)
? isLandscape
? EdgeInsets.all(
paddingTablet30(context),
)
: EdgeInsets.all(paddingTablet30(context))
: EdgeInsets.all(paddingMobile10(context)),
border: OutlineInputBorder(
borderSide: const BorderSide(
style: BorderStyle.solid,
),
borderRadius: BorderRadius.circular(24),
),
hoverColor: customPrimarySwatch,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(24),
borderSide: const BorderSide(
color: customPrimarySwatch,
),
),
),
);
},
),
);
}
Custom TextFormField
is the best way to use in your project with responsive
Upvotes: -1
Reputation: 637
Since you are using a variable in InputDecoration, you should not declare InputDecoration with const keyword.
Upvotes: 1
Reputation: 1109
Oh I see so you have this
class TextInput extends StatelessWidget {
const TextInput({
Key? key,
required this.inputController,
required this.label,
}) : super(key: key);
final TextEditingController inputController;
final String label;
@override
Widget build(BuildContext context) {
return TextFormField(
controller: inputController,
keyboardType: TextInputType.text,
// Notice the const here right?
// So the idea is that decoration objects could rebuild to either change one thing or the other, so 'label' here cannot be a constant
//So to solve this InputDecoration should not have const.
decoration: const InputDecoration(
border: UnderlineInputBorder(),
prefixIcon: Icon(Icons.phone),
labelText: label,
),
validator: (value) {
return Validation.required(value);
},
);
}
}
Upvotes: 2