I want to create a view with a TextField whose default behavior is disabled (i.e. I don't enable the default keyboard on click).
I created my own keyboard because it allows me to do specific actions for my application.
The keyboard works well and populates the TextField.
My problem
I can't manage the blinking cursor in the TextField. Indeed when I type on my keyboard the cursor follows my text so no problem.
On the other hand, if I decide to click manually in the middle of my text, the cursor moves but the new characters entered do not go to the location of the cursor.
How to do this ?
What does it look like ?
My code
My TextField Widget:
InputAtom(
autofocus: true,
controller: controllerInput,
placeholder: "Placeholder",
fontSize: 35,
keyboard: TextInputType.none,
enableInteractiveSelection: true,
showCursor: true,
cursorColor: Colors.red,
enableSuggestions: false,
autocorrect: false,
),
My button keyboard example:
KeyboardButtonAtom.numeric({
Key? key,
required String text,
required TextEditingController controller,
}): super(
key: key,
text: text,
controller: controller,
onPressed: (){
// Here I add the number typed on the keyboard after
controller.text += text.toString();
// Here the cursor moves to the end of my controller.text
controller.selection = TextSelection.collapsed(offset: controller.text.length);
print(controller.selection.baseOffset);
}
);
How to retrieve the cursor position when I type somewhere by hand in my TextField to be able to add my numbers from the cursor position?
EDIT
In my KeyboardButtonAtom, I do that and it works. Thanks to #Kaushik Chandru
Here is the code that works regardless of the position of the cursor even placed by hand in the middle of your character string
String textBeforeCursor = controller.text.substring(0, controller.selection.baseOffset);
String textAfterCursor = controller.text.substring(controller.selection.extentOffset);
controller.text = textBeforeCursor + text.toString() + textAfterCursor;
int cursorPosition = textBeforeCursor.length + 1;
controller.selection = TextSelection.collapsed(offset: cursorPosition);
To get the current position of the cursor you can try
var cursorPos = _textEditController.selection.base.offset;
String textAfterCursor = _textEditController.text.substring(cursorPos);
String textBeforeCursor = _textEditController.text.substring(0, cursorPos);
_textEditController.text = textBeforeCursor + "someText" + textAfterCursor;
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
Related
How do I show the Text Selecting Bar by default in Flutter without the user actually long pressing or double tapping in the Text Area? I am trying all possibilities in SelectableText Widget and similar, but, its not working. Could anyone help me with this?
For an example, I have A TextEditingController called myController:
TextField(
controller: myController,
onTap: () => myController.selection = TextSelection(baseOffset: 0, extentOffset: _controller.value.text.length),
)
basicaly, you need to set the selection property with a TextSelection from the baseOffset to the extentOffset.
Is there an option to select the text written in TextFormField or TextField on double clicking the field in a Windows App made in Flutter?
Because currently it only works if the text is double clicked, whereas normally in windows application clicking anywhere in the text field selects the entire text written.
Put your TextField inside GestureDetector
GestureDetector(
onDoubleTap:() {
if(_controller.text.isNotEmpty) {
_controller.selection = TextSelection(baseOffset: 0, extentOffset:_controller.text.length);
}
},
child: TextField(controller: _controller, ),
)
Wrap the textfield with an inkwell to provide a double tap. Then on double tap set the selection of the textfield
InkWell(
onDoubleTap:(){
setState((){
_textController.selection = TextSelection(baseOffset:0, extentOffset: _textController.text.length);
});
},
child:TextField(
controller: _textController,
)
)
You Dont need any other extra Widgets. Its pretty simple,You can use onTap property inside of TextField:
TextField(
controller: _controller,
onTap: () {
_controller.selection = TextSelection(baseOffset: 0, extentOffset: _controller.text.length);
}
)
like i have an edit profile page and inside text form field i populate textform field with existing data but when i press on that textform field i want my cursor to start from the last index of my pre loaded data but the keyboard cursor moves to starting point is there a way to achieve this.
this is my text form field
TextFormField(
decoration:
const InputDecoration(hintText: "First Name"),
validator: (value) {
if (value == null || value.isEmpty) {
return "Please enter your first name";
} else {
return null;
}
},
onChanged: (value) {
firstName = firstNameController.text;
if (firstName.isNotEmpty) {
firstName =
"${firstName[0].toUpperCase()}${firstName.substring(1)}";
firstNameController.selection =
TextSelection.fromPosition(
TextPosition(offset: firstName.length));
}
},
controller: firstNameController..text = firstName,
),
i am able to populate data inside textform field but the problem is when i press on textformfield i want my keyboard starting point to be at the last index of this populated data but keyboard cursor moves to the starting point no matter what need some help here thanks.
You can use selection like this
firstNameController.selection = TextSelection.fromPosition(
TextPosition(
offset: firstNameController.text.length));
Update: this problem may be because of setting the TextField's 'readOnly' attribute to true. If so, I still need to make sure the keyboard does not pop up, since I set readOnly to true to disable the keyboard.
BACKGROUND
My app adds letters and newlines from a custom button widgets to a display that has a TextField widget. I do not use a keyboard for this. I use the Provider package and a ChangeNotifier called AppBrain to manage state. AppBrain has the text information and edits it when a letter is selected from the selection bar.
The textfield is a scrollable widget when there are too many lines to fit in its dimensions. But whenever I add letters and a new line of text is created, the textfield does not scroll down and the cursor and edited line is obscured.
I would like to know an easy way to scroll until the cursor is visible again. (When the cursor is at the end of the text, I can scroll to the bottom. When it is in the middle of the text, I just need to scroll it one line down.)
POSSIBLE FIXES
When I reenable the keyboard to edit the TextField, it does it automatically. If anyone knows how the keyboard edits the TextField, I might be able to add that to my addWord function.
I tried using a ScrollController to scroll the TextField using its animateTo() function. The problem I have is that I usually need to just scroll down 1 line, but I don't have the exact pixel height of my lines of text. I also don't know when a line wraps to a new line, which would require a scroll down.
Perhaps if I had the position of my cursor, I could use it along with my TextField's dimensions to scroll down accordingly.
Picture of my app
CODE
Textfield widget in Text Display
Portion of code in Text Display
...
Positioned(//Text Display
top:0,
left:0,
width:kScreenDim.dx,
height:290,
child: Container(
color: kAppBarBackgroundColor,
child: Container(
padding: EdgeInsets.only(left: kTextMargin),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft:Radius.elliptical(17,20),
topRight: Radius.elliptical(17,20)
),
color:kTextDisplayColor
),
child: Consumer<AppBrain>(
builder: (context,appBrain, child)=> TextField(// <<=====
controller: appBrain.textDisplayController,
scrollController: appBrain.textDisplayScrollController,
readOnly: true,
autofocus: true,
showCursor: true,
maxLines: null,
decoration: null,
cursorColor: Colors.red,
style: TextStyle(fontSize: kTextFontSize,)
),
),
),
),
),
...
Enter Button
Example of a button that adds a letter to the TextField
BottomButton(//ENTER BUTTON
onPressed: () {
var appBrain = Provider.of<AppBrain>(context, listen:false);// <<===
appBrain.addWord('\n');
},
label: 'Enter',
color: kEnterButtonColor,
)
App Brain
Relevant portions of AppBrain, a ChangeNotifier. The main summary of addWord is that I directly edit textDisplayController.text and textDisplayController.selection.
class AppBrain with ChangeNotifier {
...
TextEditingController textDisplayController = TextEditingController();
ScrollController textDisplayScrollController = ScrollController();
...
...
void addWord (String aWord){//Inserts/replaces word into text of TextDisplay
//DIRECTLY EDITS textDisplayController.text and textDisplayController.selection
String displayText = textDisplayController.text;
List<int> selectionRange = getSelectionRange();
int cursorCharIndex = selectionRange[0]; //position in text
//position in _numTChars
int newCursorDisplayIndex = getCursorDisplayIndex(cursorCharIndex);
//Update text and _numTChar.
//If there is a highlighted selection of text to be replaced,
if (selectionRange[0]!=selectionRange[1]){
int lidx = selectionRange[0];
int ridx = selectionRange[1];
int lDisplayIdx = getCursorDisplayIndex(lidx);
int rDisplayIdx = getCursorDisplayIndex(ridx);
textDisplayController.text = displayText.substring(0,lidx) + aWord; <<===
if (ridx < displayText.length) {
textDisplayController.text += displayText.substring(ridx);
}
_numTChars[lDisplayIdx] = aWord.length;
_numTChars = _numTChars.sublist(0, lDisplayIdx+1) +
_numTChars.sublist(rDisplayIdx);
}else {//Insert character at the cursor
if (displayText.length == 0 || cursorCharIndex == displayText.length) {
textDisplayController.text += aWord;
} else {
textDisplayController.text = displayText.substring(0, cursorCharIndex)+
aWord + displayText.substring(cursorCharIndex);
}
_numTChars.insert(newCursorDisplayIndex, aWord.length);
}
//place the cursor in the correct position.
cursorCharIndex += aWord.length;
// <<===
textDisplayController.selection = TextSelection(
baseOffset: cursorCharIndex,
extentOffset: cursorCharIndex
);
notifyListeners();
}
...
}
When keyboard pops up it covers bottom of you widget. you should use MediaQuery to get bottom padding after keyboard pops up.
wrap your page in a Padding widget and set the bottom like this.
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: YourWidget()
when keyboard is not visible the value of
MediaQuery.of(context).viewInsets.bottom is zero, but when keyboard pops up the value changes to somethong like 253.6.
I have a textfield controller in Flutter and wish to return the position which the cursor occupies in the textfield?
Keep in mind a user may have typed in text then moved the cursor back along the text to say edit the text.
TextField(
onChanged: (value) {
//TODO - Return Cursor Position
}
),
the cursor posistion in text field
first make controller for text field now
TextField(
onChanged: (value) {
int cursorPos = _textController.selection.base.offset;
print(cursorPos);
//TODO - Return Cursor Position
}
),