I have created a custom TextField, where there need to be the following things:
- The possibility to pass a custom controller, so that when the user scans a barcode, I can update the text with the scanned test
- A focus node, so that I can customize the close button
- The possibility to pass an initial value
For this reason, I have created the following custom TextField:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:myapp/app/components/material/icon.view.dart';
import 'package:myapp/app/components/text/text.view.dart';
import 'package:myapp/app/localizations/app_localizations.dart';
import 'package:myapp/theme/colors.extensions.dart';
import 'package:myapp/theme/icons.dart';
import 'package:myapp/theme/styling.extensions.dart';
class CustomTextField extends StatefulWidget {
CustomTextField({
super.key,
this.initialValue,
this.updateValue,
this.textEditingController,
required this.orientation,
});
dynamic initialValue;
Function? updateValue;
TextEditingController? textEditingController;
Orientation orientation;
@override
State<CustomTextField> createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
TextEditingController controller = TextEditingController();
FocusNode focusNode = FocusNode();
@override
void initState() {
controller = TextEditingController(text: widget.initialValue == null ? null : '${widget.initialValue}');
super.initState();
}
@override
Widget build(BuildContext context) {
(widget.textEditingController ?? controller).selection =
TextSelection.fromPosition(TextPosition(offset: (widget.textEditingController ?? controller).text.length));
return SizedBox(
width: MediaQuery.of(context).size.width,
height: 55,
child: Stack(
children: [
KeyboardActions(
tapOutsideBehavior: TapOutsideBehavior.opaqueDismiss,
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
nextFocus: false,
actions: kIsWeb != true
? [
KeyboardActionsItem(
focusNode: focusNode,
displayArrows: false,
toolbarButtons: [
(node) {
return GestureDetector(
onTap: () {
node.unfocus();
},
child: Padding(
padding: CustomPadding.p10(),
child: CustomText(
AppLocalizations.instance.translate('Close'),
),
),
);
}
],
),
]
: [],
),
child: TextField(
focusNode: focusNode,
enableSuggestions: false,
autocorrect: false,
controller: widget.textEditingController ?? controller,
cursorColor: CustomColors.blue,
onChanged: (value) {
setState(() {
(widget.textEditingController ?? controller).text = value;
if (widget.updateValue != null) {
widget.updateValue!(value);
}
});
},
onSubmitted: (value) {
FocusManager.instance.primaryFocus?.unfocus();
},
style: CustomTextStyle.custom(fontSize: 24, color: Colors.black),
textAlignVertical: TextAlignVertical.top,
decoration: InputDecoration(
contentPadding: CustomPadding.ltrb(10, 8, 10 + ((widget.textEditingController ?? controller).text.isNotEmpty ? 28 : 0), 8),
isDense: true,
filled: true,
hintStyle: CustomTextStyle.custom(color: CustomColors.darkGrey, fontSize: 20),
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: CustomColors.blue, width: 2),
borderRadius: BorderRadius.circular(10),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: CustomColors.darkGrey,
width: 1.5,
),
borderRadius: BorderRadius.circular(10),
),
),
),
),
if ((widget.textEditingController ?? controller).text.isNotEmpty)
SizedBox(
height: 49,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: CustomPadding.only10(PaddingPosition.r),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
HapticFeedback.heavyImpact();
if (widget.updateValue != null) {
widget.updateValue!('');
}
setState(() {
(widget.textEditingController ?? controller).text = '';
});
},
child: CustomIcon(
icon: SvgFont.xmark_solid,
color: CustomColors.red,
),
),
),
],
),
)
],
),
);
}
}
However, this causes a problem with the cursor, since it keeps going to the end of the string instead of staying where I'm writing. I tried removing all custom controller management and the initial value, and the problem is fixes, but I need those inputs. Moreover, if I don't set the selection in the build function, the text field keeps losing focus and it becomes impossible to write anything.
I would like to have the three points I listed at the beginning, but I would also like to fix the cursor and the selection so that if I want to edit the middle part of the string, I can do it without having to move the cursor at each character I type.
How can I achieve this?