Just over 2 years ago, I posted this article:
http://delphi.radsoft.com.au/2013/10/moving-controls-into-view-when-the-virtual-keyboard-is-shown/
Well, a little water has passed under the bridge since then, in terms of the changes to Delphi (I think I used XE5 for that article?), and in terms of my thinking. A recent task at work had me thinking there could be a more straightforward approach. This article, and the associated code goes a long way to solving that.
Delphi now has (not sure if it did before, and I’m not going to look), a means of responding to when the virtual keyboard is shown or hidden, without actually assigning a handler in a form (i.e. the OnVirtualKeyboardHidden and OnVirtualKeyboardShown events). I decided to create a manager class that would take care of pretty much everything; all that needs to be done is for the OnFocusChanged handler to be assigned to the manager.
The manager class is called TVKControlManager. To respond to the virtual keyboard being hidden/shown, it subscribes to the TVKStateChangeMessage. (See here for information about the message manager).
When the virtual keyboard is shown, the manager keeps a copy of the keyboard bounds, and calls PositionAdjust. PositionAdjust determines what the focused control is, and finds the closest parent that is either a scrollbox, or the furthest up the chain that is non-nil. If the position hasn’t already been adjusted, it saves the parents position, and the height of its parent (i.e. the next level up). It then adjusts the Y value of the “parents” position “upwards”, to just above the virtual keyboard bounds, and also makes sure the height of the parent’s parent is increased to allow for the shift.
When the virtual keyboard is hidden, the position is “restored” in PositionRestore, where everything is put back the way it was before the virtual keyboard was shown.
When the focus changes, (but the virtual keyboard remains visible), the PositionAdjust is called again in case there’s any adjustment that needs to be done.
I’ve also added in events in case the end-user wishes to do some “tweaking” after the position is adjusted or restored.
There’s a caveat in order for this to work properly: If you’re using a scrollbox on which you place your controls, the Align property cannot be Top, or Client (at least; these are the two that come to mind immediately). The reason for this is that attempting to set the Y value of the Position property will result in it being reset when FMX realigns the controls. One way out of this is to have Align set to Bottom, and explicitly set Position.Y to wherever it needs to be when the form is shown, or when the orientation changes. Orientation changes result in the virtual keyboard being hidden, so the old issue of controls being out of position when the virtual keyboard is visible and the orientation changes, has now disappeared.
Instead of including code snippets here, I’ve included the entire example project. I’ve tested it on iOS simulator, device (iPhone 6S) and an Android device (Nexus 5). Note: The “Previous” and “Next” buttons will not appear on iPad. For some reason or another, the FMX code does not allow the virtual keyboard toolbar on iPad; I may visit this issue in another post.
Feel free to make comments/suggestions.
Well done Dave.
As you say it is much less complicated and, with a few changes to see if it solved my main difficulty, I have found it to work pretty much as I need.
I structured my test with a VertScrollBox set to Client. That contains a Panel set to MostTop and with a height greater than my device (Nexus 7). The Panle contains the other controls from your sample but spaced out a little more from top to bottom.
This means that Edit2 (aligned Bottom) is out of sight. Bi=ut it can be scrolled up and when focused the keyboard pops-up and the Edit scrolls correctly. Yay!
But my experience differs from your description on two matters:
1) A change of orientation does NOT hide the VKbd and the Panel (in my case) appears to be returned to its original position.
2) The virtual keyboard Previous and Next buttons do not show here. Should they? Have I missed something?
Displaying the additional buttons on their panel requires use of SetToolbarEnabled:
LService.AddButton(‘Previous’, GotoPrevious);
LService.AddButton(‘Next’, GotoNext);
LService.SetToolbarEnabled(true);
Enable and disable according to your need. I principally use these buttons only one screen with many edits.