What Output field to choose in calculator build with flutter - flutter

I am making a calculator app. I want to ask which widget can I use to display numbers. If I use Text then I can't edit it with cursor and if I use TextField keyboard pops up.

I found an implementation of a EditableText that might work for you. Just drop in this code:
class NoKeyboardEditableText extends EditableText {
NoKeyboardEditableText({
#required TextEditingController controller,
#required TextStyle style,
#required Color cursorColor,
bool autofocus = false,
Color selectionColor
}):super(
controller: controller,
focusNode: NoKeyboardEditableTextFocusNode(),
style: style,
cursorColor: cursorColor,
autofocus: autofocus,
selectionColor: selectionColor,
backgroundCursorColor: Colors.black
);
#override
EditableTextState createState() {
return NoKeyboardEditableTextState();
}
}
class NoKeyboardEditableTextState extends EditableTextState {
#override
void requestKeyboard() {
super.requestKeyboard();
//hide keyboard
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
}
class NoKeyboardEditableTextFocusNode extends FocusNode {
#override
bool consumeKeyboardToken() {
// prevents keyboard from showing on first focus
return false;
}
}
This will create a EditableText that does not open the keyboard, but you can still move the cursor as normal. To add text, I would use a combination of the text(), value(), selection() methods for the TextEditingController. First get the value in the field, then get the position of the cursor with selection(), input whatever text you want at the selection index, and finally set the text for the controller to the resulting string.
Let me know if this helps!

So, you can try this one
TextField(showCursor: true, readOnly: true);

Related

Flutter: How to hide TextField text pointer (cursor) when use initial value text (Android)

Use case: Messaging app you edit your message: keyboard, blinking cursor and initial text appears but pointer (cursor) is not
But on Flutter when you use initial text (or via textController) there are always pointer(cursor) which is not wanted
Example
Steps to reproduce:
run flutter create bug
edit main.dart to replace center text (line 100) to MyStatefulPage(),
class MyStatefulPage extends StatefulWidget {
#override
State<MyStatefulPage> createState() {
return _MyStatefulPageState();
}
}
class _MyStatefulPageState extends State<MyStatefulPage> {
TextEditingController controller;
#override
void initState() {
super.initState();
controller = new TextEditingController();
controller.text = 'My Initial Text';
}
#override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
border: InputBorder.none
),
// showCursor: false,
controller: controller,
autofocus: true,
maxLines: 8,
);
}
}
With that code when you open app keyboard will appear but so will pointer(cursor) I want to hide this cursor(pointer).
Note: it's only for Android.
TextField set enableInteractiveSelection property to false can resolve this issue
TextFormField cursorHeight: 0 and cursorWidth: 0 can hide the cursor.
in textformfield use showCursor: false

disappear of the text written in the text field after pressing done

I am using a text field in my app to write comments, when the user type a text and press a button the text should be written to the database. However, I have a problem which is when I write the text then press done or return from the keyboard, the text disappear then there is no comment to be added. Is there any idea to save the value of the text in the text field even after pressing done or return?
Not sure why your input is disappearing but you can use a TextEditingController and pass that controller to a TextField.
Then access the value of the TextField using controller.text .
Here is a little example
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
String databaseText;
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: TextField(
controller: controller,
onEditingComplete: () {
databaseText = controller.text;
print(databaseText);
},
),
),
),
);
}
}
this issue happen because the TextEditingController is rebuilt after you add your text. for me I used static controller to solve this problem.
static TextEditingController textController = TextEditingController();
and I highly recommend reading this
String _text;
final formKey = GlobalKey<FormState>();
Form(
key: formKey,
child: Column(children: <Widget>[
TextFormField(
autocorrect: false,
decoration: InputDecoration(labelText: "Text:"),
onSaved: (str) => _text = str,
)
]));
Then just pass your _text variable inside your paramater as your key value.
Try modifing contentPadding in InputDecoration. For example:
contentPadding: EdgeInsets.symmetric(horizontal: 2, vertical: 0)
The corresponding Flutter bug report is #29542: "Text getting cleared when using TextEditingController AND StreamBuilder".
There, user bizz84 commented, asking:
So the reason that this works with StatefulWidget is that the state is retained even across rebuilds, so I can use it to hold my TextEditingControllers.
Is this correct?
And rrousselGit replied:
Exactly :-)
Generally speaking, don't create anything but primitives in a StatelessWidget/InheritedWIdget. For everything else, you'll need a State
So, this appears to be the official answer: if you are creating anything other than primitives, you will need a State.

Style part of text in TextField

I'm implementing a custom text field and I would like to style certain keywords (namely hashtags) differently than the rest of the text as the user type them in.
Kind of like this:
Is there a way to do that in Flutter ?
This question is very similar to How to change color of particular text in a text field dynamically?
I answered it there in: https://stackoverflow.com/a/57846261/5280562
In short: you can extend EditableText widget including its EditableTextState class and override buildTextSpan method.
Below is a working example called AnnotatedEditableText that I use in my app.
You need to supply a list of Annotation objects which describe which ranges of text need to be highlighted and what style to use.
import 'package:flutter/widgets.dart';
class Annotation extends Comparable<Annotation> {
Annotation({#required this.range, this.style});
final TextRange range;
final TextStyle style;
#override
int compareTo(Annotation other) {
return range.start.compareTo(other.range.start);
}
#override
String toString() {
return 'Annotation(range:$range, style:$style)';
}
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
TextSelectionControls selectionControls,
this.annotations,
}) : super(
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: true,
autofocus: true,
selectionColor: selectionColor,
selectionControls: selectionControls,
onChanged: onChanged,
onSubmitted: onSubmitted,
);
final List<Annotation> annotations;
#override
AnnotatedEditableTextState createState() => new AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
#override
AnnotatedEditableText get widget => super.widget;
List<Annotation> getRanges() {
var source = widget.annotations;
source.sort();
var result = new List<Annotation>();
Annotation prev;
for (var item in source) {
if (prev == null) {
// First item, check if we need one before it.
if (item.range.start > 0) {
result.add(new Annotation(
range: TextRange(start: 0, end: item.range.start),
));
}
result.add(item);
prev = item;
continue;
} else {
// Consequent item, check if there is a gap between.
if (prev.range.end > item.range.start) {
// Invalid ranges
throw new StateError(
'Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
));
}
// Also add current annotation
result.add(item);
prev = item;
}
}
// Also check for trailing range
final String text = textEditingValue.text;
if (result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
));
}
return result;
}
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
if (widget.annotations != null) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
It's also available in this Gist: https://gist.github.com/pulyaevskiy/d7af7217c2e71f31dfb78699f91dfbb5
I actually had the same problem and found the AnnotatedEditbleText which helped me a lot.
I published the helpful package to solve this kind of problem.
https://pub.dev/packages/hashtagable
The TextField does not provide that functionality.
https://pub.dartlang.org/packages/zefyr can do that though.
I think there are some more ''hard'' ways to do this
The first one:
Make a row widget, add a part of the String until the word you want to highlight, add the special word, style it and add the rest of your string.
Or, you could try RichText
Günter post it about the zefyr package, I didn't use it yet, but if suits you, I'll be glad that helped

Flutter Widget Focus issue

I've create a custom widget for time picking.
The widget contains an icon which opens a TimePicker, and a TextFormField so the user can type the time value manually.
This is how it looks like:
When the user types a value it immediately validated and also when the focus is off, it validate the value and update the field with correct time format.
For example, if the user types 8 and then clicks next widget, it will update to 8:00
Checkout the form image with 2 TimePickers:
What I want is that when user types StartTime, and then clicks the keyboard Next button, the focus will move to the EndTime picker. Then when the user clicks Next button on the EndTime Picker the focus will move to the next widget in the form
The problem is that the FocusNode is inside the TimePicker custom widget (which is StateFull) and I couldn't figure out how it can be exposed outside of it.
You can see the code for it here:
https://github.com/moti0375/tikal_time_tracker/blob/develop/lib/ui/time_picker.dart
Any idea will be appreciated.
Finally I've figured it out,
Instead of creating the FocusNode inside the picker widget (a child widget), I've created the FocusNode in the parent widget (the form) and provide it to the child widget in its constructor, by this the focus node created in the parent widget context.
Then, I've added a request focus method to the child widgets so the parent can call them and FocusScope.of(context).requestFocus(focusNode); is called inside the child widgets but on the focusNode that provided by the parent widget.
Here is a portion of the code:
Child widget:
class TimeTrackerTimePicker extends StatefulWidget {
final FocusNode focusNode;
TimeTrackerTimePicker({ this.focusNode});
//This can be called from the parent widget with the parent context
void requestFocus(BuildContext context){
print("${this.pickerName} requestFocus...");
FocusScope.of(context).requestFocus(focusNode);
}
....
....
#override
State<StatefulWidget> createState() {
return TimePickerState();
}
}
State class:
class TimePickerState extends State<TimeTrackerTimePicker> {
#override
Widget build(BuildContext context) {
return Container(
....
child: new Flexible(
child: new TextFormField(
textInputAction: TextInputAction.next,
focusNode: widget.focusNode, //linking to the focusNode
onFieldSubmitted: onSubmitButtonClicked,
decoration: InputDecoration(
hintText: widget.hint != null ? widget.hint : "",
contentPadding:
EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0))),
maxLines: 1,
controller: pickerController))
)
}
}
Then in the parent widget when you need to set focus:
FocusNode focusNode;
TimeTrackerTimePicker timePicker;
#override
void initState() {
super.initState();
focusNode = new FocusNode();
timePicker = new TimeTrackerTimePicker(focusNode: focusNode);
}
.....
//request focus when required..
void requestPickerFocus(){
timePicker.requestFocus(context);
}
FocusScope.of(context).unfocus()

How to listen to keyboard on screen Flutter?

I am building a mobile app, I want to remove a widget when the keyboard appears on the screen, i.e when the input text field is on focus.
I have tried to use RawKeyboardListener but that doesn't seem to work, my code is as below:
new Container(
child: new RawKeyboardListener(
focusNode: new FocusNode(),
onKey: (input) => debugPrint("*****KEY PRESSED"),
child: new TextField(
controller: new TextEditingController(),
),
),
);
You can use this simple check:
MediaQuery.of(context).viewInsets.bottom == 0
The keyboard is closed when this returns true, otherwise it's open.
Be aware to take the context of the whole screen (Scaffold for example) and not only from one widget.
This is how you integrate that check to your code:
Visibility(
child: Icon(Icons.add),
visible: MediaQuery.of(context).viewInsets.bottom == 0,
)
The keyboard will automatically appear when the text field is focused. So you can add a listner to the focusnode to listen the focus change and hide respective widget.
Example:
void _listener(){
if(_myNode.hasFocus){
// keyboard appeared
}else{
// keyboard dismissed
}
}
FocusNode _myNode = new FocusNode()..addListener(_listner);
TextField _myTextField = new TextField(
focusNode: _mynNode,
...
...
);
new Container(
child: _myTextField
);
I used the package keyboard_visibility
Then I wrapped my TextField with a KeyboardListener implemented as follows:
class KeyboardListener extends StatefulWidget {
final Widget child;
final void Function(bool) onChange;
KeyboardListener({#required this.child, #required this.onChange});
#override
_KeyboardListenerState createState() => _KeyboardListenerState();
}
class _KeyboardListenerState extends State<KeyboardListener> {
int _sId;
KeyboardVisibilityNotification _kvn;
#override
void initState() {
super.initState();
_kvn = KeyboardVisibilityNotification();
_sId = _kvn.addNewListener(
onChange: widget.onChange,
);
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void dispose() {
_kvn.removeListener(_sId);
super.dispose();
}
}
You can use this library keyboard_visibility: ^0.5.6 at :
https://pub.dev/packages/keyboard_visibility
For execute your code, insert this in the initState()
KeyboardVisibilityNotification.addNewListener(
onChange: (bool visible) {
print(visible);
this.setState(() {
keyboardIsOpen = visible;
});
},
);
Whenever keyboard is open or closed, the library calls onChange method with the visibility boolean.
A widget that calls a callback whenever the user presses or releases a key on a keyboard.
A RawKeyboardListener is useful for listening to raw key events and hardware buttons that are represented as keys. Typically used by games and other apps that use keyboards for purposes other than text entry.
For text entry, consider using a EditableText, which integrates with on-screen keyboards and input method editors (IMEs).
const RawKeyboardListener({
Key key,
#required FocusNode focusNode,
#required ValueChanged<RawKeyEvent> onKey,
#required Widget child
})
Creates a widget that receives raw keyboard events.
For text entry, consider using a EditableText, which integrates with on-screen keyboards and input method editors (IMEs).
Implementation
const RawKeyboardListener({
Key key,
#required this.focusNode,
#required this.onKey,
#required this.child,
}) : assert(focusNode != null),
assert(child != null),
super(key: key);