Multiple entity-bound CupertinoTextFields that save on focus out - ios

I have a list of some entries I want edit on focus out. I createe FocusNode for each entry, CupertinoTextField for each entry too.
var textField = (UserMotivator um) {
var controller;
var focusNode = new FocusNode();
focusNode.addListener(() {
if (!focusNode.hasFocus) {
post(um);
}
});
var controller = TextEditingController(text: um.text);
return CupertinoTextField(
focusNode: focusNode,
controller: controller,
onChanged: (String value) {
um.text = value;
}
);
};
For some weird reason, in simulator (not tested on real device), when I click on many of these TextFields, I get this:
How do I bound a focus out even to a TextField without using FocusNode/ without having all of these cursors blinking?

So I resolved the issue I think. The reason it was buggy was that I was on v1.1.8, after updating to v1.5.4 it somehow got fixed, was not perfect but was better. After I moved the FocusNodes creation code form build to initState method it got even better but the cursor was still blinking at the start of the TextField. This was because I had called setState in the onChange handler, which somehow caused the TextField to redraw and act so weirdly.

Related

Flutter restarts state of TextField when keyboard is shown and then gone

So I'm working on a TextField with scoped_model. I moved the controller to the Model class, and I'm trying to change the state of a Text with the text the user inputs on said TextField. But when I close the keyboard, the state changes and the TextField is now empty, so nothing is seen on the Text widget either. This is my code:
CupertinoTextField(
controller: model.lastNameController,
onChanged: (text) => model.changeShortLastNameState(lastName: text),
),
And this is the relevant code on my Model
final lastNameController = TextEditingController();
void changeShortLastNameState({String lastName}) {
var splitLastName = lastName.split(' ');
var shortLastName = splitLastName[0];
this.shortLastName = shortLastName;
notifyListeners();
}
I found someone on the flutter github with the same issue, but they sent him to SO, and I haven't been successful on finding a question by the same guy. Does anyone know how to solve this issue? Thanks.
Use the deceleration of text editing controller out side of build function.

Managing events in flutter's TextFormField

In Flutter project, I need to listen to the input text in TextFormField and do certain actions, especially when user put some character (eg. space) in this filed or when he request focus. When this kind of event happen, I need to modify filed's value.
I know there is a property called controller but I don't know how to use it in this case.
Thank you in advance.
You can specify a controller and focus node, then add listeners to them to monitor for changes.
Ex:
Define controllers and focus nodes
TextEditingController _controller = new TextEditingController();
FocusNode _textFocus = new FocusNode();
Define listener function
void onChange(){
String text = _controller.text;
bool hasFocus = _textFocus.hasFocus;
//do your text transforming
_controller.text = newText;
_controller.selection = new TextSelection(
baseOffset: newText.length,
extentOffset: newText.length
);
}
Add listner to controller and focusnode at initState
// you can have different listner functions if you wish
_controller.addListener(onChange);
_textFocus.addListener(onChange);
Then you can use it as
new TextFormField(
controller: _controller,
focusNode: _textFocus,
)
Hope that helps!
If you are just trying to transform the input to other form in TextFormField, you better use "TextInputFormatter". Using a listener with TextController cause a lot of troubles. Take a look at my sample code see if that helps you. btw, The last line of code is just trying to move the cursor to the end of text.
TextFormField(inputFormatters: [QuantityInputFormatter()])
class QuantityInputFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
final intStr = (int.tryParse(newValue.text) ?? 0).toString();
return TextEditingValue(
text: intStr, selection: TextSelection.collapsed(offset: intStr.length),);
}
}

ICommand not always firing when tab selected

I have a simple ActionBar with 3 tabs attached. When a tab is clicked, the fragment is inflated and the view shows. The tab being click event is fired using an event. Initially, the first fragment is inflated, but the others respond and inflate if clicked.
If I change the event being fired to an ICommand, only the last fragment is inflated and then if I click on the first tab, that and the last are inflated. Never the second.
My code is this
ICommand TabClicked
{
get
{
return new RelayCommand(() =>
{
tab.TabSelected += (object sender, ActionBar.TabEventArgs e) => TabOnTabSelected(sender, e);
});
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
fragments.Add(new TODFragment());
fragments.Add(new ConditionsFragment());
fragments.Add(new ResultsFragment());
AddTabToActionBar("Time", Resource.Drawable.crucifix_colour);
AddTabToActionBar("Conditions", Resource.Drawable.weather_colour);
AddTabToActionBar("Results", Resource.Drawable.tod_colour);
}
void AddTabToActionBar(string text, int iconResourceId)
{
tab = ActionBar.NewTab().SetTag(text).SetText(text).SetIcon(iconResourceId);
/* uncomment and comment out one of the two below to see the difference in operation */
tab.TabSelected += TabOnTabSelected;
//tab.SetCommand<ActionBar.TabEventArgs>("TabSelected", TabClicked);
ActionBar.AddTab(tab);
}
void TabOnTabSelected(object sender, ActionBar.TabEventArgs tabEventArgs)
{
var tabNo = sender as ActionBar.Tab;
var frag = fragments[tabNo.Position];
tabEventArgs.FragmentTransaction.Replace(Resource.Id.frameLayout1, frag);
}
Am I missing something fundamental here in the difference between ICommands and Events or is it something else?
I'm using Xam.Android and MVVMLight
I found the answer. When I create the partial class I define the UI objects like this (or something like this at least)
EditText myEditText;
EditText MyEditText = myEditText ?? (view.FindViewById<EditText>(Resources.Id.myEdit);
This is fine, but it does mean that once defined, it doesn't get redefined.
Not a problem if the UI is not really going to change, but every time an action tab is pressed, the fragment is refreshed. Only problem is the Id isn't changing as myEditText is not null.
The answer is add a method in the UI definition code that nulls the objects then in the main code, when the UI disappears, call the nulling method. Everything works then

ListGrid put focus in the FilterEditor

I have a ListGrid defined like this:
ListGrid lgrid = new ListGrid();
ListGridField first = new ListGridField("first",first");
ListGridField second = new ListGridField("second ",second ");
lgrid.setFields(first, second);
lgrid.setShowFilterEditor(true);
¿How can i put the keyboard focus in the first filter editor field after i call show() in the layout?
Thxs in advance.
Depending on what your use case is (which would be useful to provide a more focused answer), the solution you posted might not be what you really need, because if you scroll on your ListGrid, it could trigger a new data fetch (if there are more records to show), and move the cursor to the filter editor as a result (if your user is editing some records at that point, the cursor moving to the filter row is not what she would want to happen!!).
In such a case, you probably just want to call grid.focusInFilterEditor("fieldToFocus") after the listGrid.show() statement or in the ClickHandler of some button you use to fetch the data, etc.
Anyway, you don't need the Timer either. This works:
listGrid.addDataArrivedHandler(new DataArrivedHandler() {
#Override
public void onDataArrived(DataArrivedEvent event) {
grid.focusInFilterEditor("fieldToFocus");
}
});
I got the solution, its focusInFilterEditor, this is an example to set the focus after the data arrived to the grid:
// Put the focus on the first listGrid field when is loaded
listGrid.addDataArrivedHandler(new DataArrivedHandler() {
#Override
public void onDataArrived(DataArrivedEvent event) {
Timer t = new Timer() {
public void run() {
if(listGrid.getFilterEditorCriteria() == null){
listGrid.focusInFilterEditor("fieldToFocus");
}
}
};
t.schedule(600);
}
});

Table Cell seems to lose binding when the table is pulled up

I have an issue with a Xamarin IOS project using MVVMCross. There is a MvxTableViewController which displays a variety of MvxTableViewCells. When the user touches inside a text field in a cell and then pulls the table view controller up, the data in the focused cell disappears. As far as I can tell, there is no application code executing after this gesture.
I've attached screens showing the data before, during and after the screen is pulled up. There are no messages written to the console during this event.
Any idea where I should Look for this issue?
Update
Here is the code used to bind the values in the cell's constructor. There's a bit more than just binding going on, but I included it all in case it is impacting the issue.
Thanks!
public BaseComponentCell (IntPtr handle) : base (handle)
{
this.DelayBind (() => {
ComponentValueTextField.ShouldReturn += (textField) => {
textField.ResignFirstResponder ();
var component = (BaseComponent)DataContext;
if(component.DoneEditingCommand!=null){
component.DoneEditingCommand.Execute(null);
}
return true;
};
var myComponent = (BaseComponent)DataContext;
if (myComponent.DisplayNumberPadKeyboard)
{
ComponentValueTextField.KeyboardType = UIKeyboardType.NumberPad;
}
var set = this.CreateBindingSet<BaseComponentCell, BaseComponent> ();
set.Bind(ComponentNameLabel).To(c=>c.ComponentName);
set.Bind(ComponentValueTextField).To(c=>c.ComponentValue);
set.Bind(ComponentValueTextField).For(f => f.Enabled).To(c => c.IsEnabled);
set.Bind(this).For(bc=>bc.IsSecure).To(c=>c.IsSecure);
set.Apply();
});
}

Resources