Curious problem:
Two UITextFields, managed by a single controller, enabled for keyboard input. If one enters a value in field #1 and presses "Next" on the KB, the blinking cursor jumps to field #2 just fine and everything's OK. But (only in iOS 5) if one touches field #2 instead of pressing "Next", the cursor jumps to field #2 but doesn't blink and the KB is dead.
Stepping through the code, I find that in the first case the sequence is:
textFieldShouldReturn:field#1 (which does a resign first responder for #1)
textFieldDidEndEditing:field#1 (which does a resign for #1 and a become for #2)
textFieldShouldBeginEditing:field#2
In the second case (when the field is touched vs using "Next") the sequence is:
textFieldShouldBeginEditing:field#2
textFieldDidEndEditing:field#1
textFieldShouldBeginEditing:field#2 (again)
textFieldDidEndEditing:field#2 (which does a resign for BOTH #1 and #2)
Obviously, when the resign for #2 is done that kills the KB, but WHY is iOS 5 making the call to DidEndEditing with field #2??? And how could one circumvent this?
Update
Added a hook for textFieldShouldEndEditing. It's called before textFieldDidEndEditing for field#1, but not before textFieldDidEndEditing for field#1. Though, curiously, textFieldShouldBeginEditing is called just before textFieldDidEndEditing for field#2. Smells like an out-and-out "dupe error" in the iOS code.
Update 2
iOS 5 does not handle resign/become calls out of testFieldDidEndEditing. See below for circumvention.
I came to the conclusion that iOS 5 does not (correctly) handle the case of having resignFirstResponder/becomeFirstResponder calls inside textFieldDidEndEditing. Moved the logic (more or less) to textFieldShouldReturn (touch kind of takes care of itself), and now it seems to work OK.
Related
The database application I am working on can have a window with multiple NSTextView elements for displaying and editing data. When the current spot in the database is repositioned, all of the NSTextView objects in the window need to be updated with new contents. This is done with a loop that scans each object and checks to see if it needs to be updated. If it does, the new value is calculated, then updated by using the [NSTextView setString:] method. Here is a simplified version of the code involved.
for formObject in formObjectsInWindow {
NSTextView * objectTextView = [formObject textView];
NSString * updatedValue = [formObject calculateValue];
[objectTextView setString: updatedValue];
}
This works, but if there are a lot of objects, it is somewhat slow. Probably related, the display does not update all at once, you can actually see a "ripple" as the objects are updated, as illustrated in this movie (this movie has been slowed down to 1/4 speed to make the ripple effect more pronounced, but it is definitely visible at full speed).
If you've gotten this far, you might suspect that the calculateValue method is slow, but that isn't the problem. In other places the same code is used and runs at tens of thousands of operations per second. Also, this delay only occurs during update operations, it doesn't occur when the window is first opened, even though the same calculations are required at that time. Here is an example. Notice that when I switch back to the detail view all the NSTextView objects update instantaneously, even though the record changed and all of the values are different.
My suspicion is that the [NSTextView setString:] method is updating the off-screen buffer, then immediately copying that to the on-screen buffer, so that this double buffering is happening over and over again for each item, causing the delay and ripple. If so, I'm sure there must be some way to prevent this so that the screen is only updated at the end after all of the values have been updated. It's probably something simple that I am missing, but I'm afraid I am stumped as to how this is supposed to be done.
By the way, this application does not use layer-backed views, and is not linked against the QuartzCore framework.
I brought up this question with Apple engineers at the WWDC 2018 labs. It turns out the problem is that the setString: method does not mark the NSTextView object as needing display. The system does eventually notice that the text has changed and updates the display, but this happens in an asynchronous process, hence the "ripple" effect. So the workaround is simply to add a call to setNeedsDisplay after calling setString.
[objectTextView setString: updatedValue]
[objectTextView setNeedsDisplay:YES];
Adding this one line of code fixed the problem, no more ripple effect.
I'm told that this is actually a bug, so hopefully this extra line won't be needed in future versions of macOS. As requested, a radar has been filed (41273611 if any Apple engineers are reading this).
Some years ago (2008) I wrote an online Child Support Calculator using PHP/Javascript/Ajax/css Advanced Child Support Calculator - May help to explain what I am replicating.
Some time after (2009 I think) I started writing an equivalent for Windows and am now revisiting this. The fundamentals of this version are working.
However, I have an issue with the window noticeably flickering/changing when controls are dynamically added and the window is redrawn/rebuilt.
Note! This calculator is specific to Australia.
In short I'm looking for a way, if possible, to only refresh/re-display/redraw the window after all components have been added.
Basically, the windows controls need to be dynamically added/removed depending upon the scenario (number of adults and children involved).
Adding or removing a child or adult or performing the calculation, results in a complete rebuild of the window. That is, all existing controls are destroyed and then all valid controls are added (this could perhaps be minimised via complex logic).
The issue is that controls are removed but briefly reappear (in an ordered fashion) causing the display to flicker (for want of a better description).
The following screen shots demonstrate the complexity factor (such as a child has a drop down for each defined adult), but not the flicckering(sic).
Here's a screen shot of the Initial display (OK pretty ugly at present) :-
And then if an Adult is added (note that the child now has an extra dropdown for Adult 3, the new adult):-
And now, an Adult (as above) and a Child:-
Coding wise, there is a RebuildAll function. This has two main stages. (1) The removal of the controls. (2) The rebuild (recreation) of the appropriate of the controls (Create Window, SendMessage's and then ShowWindow)
At a minimum there are 61 controls. The number of controls is
23 + ((#children * 12) - 2) + (#children * (#Adults * 8 )) + ((#adults * 10) -4). It's likely suffice to say that the number of controls increases rapidly/exponentially.
I suspect that it might be possible to postpone the ShowWindow untill after all of the builds have been done. Is the solution, as simple (theoretically) as this, assuming that this is feasible or is there another way that would circumvent the need to change all the code to remove the 'ShowWindow' and add a ShowWindow at the end of the builds?
Note replacing the individual ShowWindow's with one significantly reduced the "flicker" but didn't eliminate it. (as per Update below).
As an endnote I'm pretty sure that something should be feasible as the
windows program I have to date is a very poor reflection of the speed
of the browser/javascript version, which basically does the same thing
on windows (albeit 64bit).
Update
I went through and commented out the ShowWindows in all the AddItem???? functions and added a ShowWindows to the function that calls all the functions. This has improved matters. However, the numerous DestroyWindow calls still causes flickering when removing all of the controls. So now I guess that I'm looking for something that can disable them apparently doing an equivalent of ShowWindow.
Update 2
I have found SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); (TRUE to turn drawing back on). However, this appears to supress the DestroyWindow in that the display aspect of the control remains (the controls themselves don't appear to respond though).
By a process of elimination I have cured the flicker with a combination of ShowWindow's and WM_SETREDRAW's at pertinent points.
To briefly re-describe the issue. When adding a child or adult, or performing a calculation. The entire display is rebuilt. The rebuild basically consists of 2 phases. First, destroying the existing control windows and then adding the new/replacement set of window's controls.
The resolution was to :-
Issue a ShowWindow(hwnd,SW_SHOW); (for the main/containing
window) after all the pre-existing windows control's had been
destroyed.
Issue a WM_SETREDRAW FALSE message as per SendMessage(hwnd,
WM_SETREDRAW, FALSE, 0); before rebuilding the windows controls.
Without any ShowWindow's being used.
Build the windows controls via the various functions.
Finally, when all the windows controls have been built, issue a
ShowWindow(hwnd,SW_SHOW); (for the main/containing window).
Rather than seeing the controls appear and then disappear, "the flickering". The window is blank for a while and then the controls are displayed all at once.
I'm still confused about what is actually going on though, due to:-
After some thought I decided to use a MessageBox after all the destroys. When the message was displayed the window was blank. However, when the button was clicked and processing resumed then, in situations when the number of controls was relatively high, controls would appear and then disappear in an orderly fashion, albeit it momentarily.
My guess, is that creating a control in an area where an existing
control had been, was causing that previous control to momentarily
display.
There are some controls on windows phone that behave different on the first interaction with them than on subsequent ones. e.g. a button control takes about 3-5 seconds to initialize the required action the first time the button is pressed, however on subsequent clicks it works immediately.
Another usercontrol that adjusts its height based on the key press doesn't adjust properly the first time, however the second time it works.
Is there a way to either prepare the controls, i.e. set them in a ready state so that all the clicks behave the same, or can first click can be faked to bypass this annoying behaviour?
Also what is causing this problem?
NB:- I am testing on a Lumia 520 device.
Unfortunately There is no way to prepare the controls. Nokia Lumia 520 comes in Lower Memory Device So Its behaviour seems slow at loading first time in memory and there are so many Background tasks also runnig at a same point of time. You should try it in Higher Memory Device and see the Behaviour.
I found out from this app performance document why it was happening , http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff967560(v=vs.105).aspx#BKMK_Applicationstartup.
I have a loading panel that is set to collapsed by default and only set visible once the button is clicked. According to the document, elements in collapsed state arent added to memory, so this means the first time it needs to initialize the panel and it doesnt need to in subsequent tries.
The other UI control behaving weirdly was also due to its parent's height not being adjusted after its own height is adjusted the first time, so adjusting the parent height as well fixed it.
I have an NSTableView in which I need to be able to intercept keyboard events within an editable cell and replace the cell with strings. For example, press "a" and have the "a" intercepted and the value "Alpha" assigned when the table reloads. The actual situation is a bit more complex in that I'm also handling HID devices, but that's a whole other story. Suffice it to say, I just want to be able to go into edit mode and stop the keyboard-generated values from being displayed.
The latter part of this (displaying "Alpha") is easy, but I can't figure out the first part of the problem. If I subclass the table and make it first responder, I can receive the keyDown: event, but once the user double-clicks on a cell and starts typing, this goes silent.
Since none of the other NSTableView components (NSCell, NSTextFieldCell, etc) derive from NSResponder, I'm assuming there is an NSTextField buried in there somewhere.
So, what's the best way to filter text once the user goes into cell edit mode?
As always happens: after working on this for eight hours, reading all the docs five times, and then resorting to the net, I find the answer five minutes later:
- (BOOL)textShouldBeginEditing:(NSText *)textObject.
Sorry to consume bandwidth.
There are times when it makes sense to force an end of any edits that are currently being made. For instance, if the user is typing a value in a field on my document, and then clicks to the preview window, or chooses "Print" or "Save" from the menu.
The problem is, by forcing an end to editing (either by asking the NSWindow to make itself first responder, or by calling endEditingFor: on the window), the first responder focus is no longer on the field in question. This is disruptive to the user in some situations, where the action being taken is iterative and does not signify an end to their work on the document.
My first attempt at solving this is to pay attention whatever the current firstResponder is, and then to restore it after ending editing, by using NSWindow's "makeFirstResponder:". This works OK, but it has the undesired effect e.g. on NSTextFields of resetting the selection in the field editor to the entire length of the string contents.
Is there some trick I can use to force the entire system of "endEditing" methods to be called without disrupting the current field editor at all?
Thanks,
Daniel
Why not use your original method but also record where/what the selection range looks like and restore it after restoring the first responder?
I agree that this is the way to do it. On iPhone it is particularly important not to have the keyboard jumping up and down at inopportune moments. I have used:
[textView endEditing:YES];
[textView becomeFirstResponder];
successfully to complete pending spelling correction (as though a space were hit) before taking action on the content of a UITextView, but without any side-effects.