Home/Code tips, Uncategorized/Moving controls into view when the virtual keyboard is shown

Moving controls into view when the virtual keyboard is shown

Views:
1170

UPDATE: The demo project attached has been updated due to a couple of “glitches”. One remaining known issue is that the “Config” page doesn’t move to its original position if changing orientation when the keyboard is already showing. I’ll revisit the article when I’ve come up with a solution.

I’m sure almost everyone who develops an app for mobile devices has, or will, come across this problem: an edit control is low enough on the screen to be covered by the virtual keyboard when the user taps on the edit control. When I first started using iOS, I figured that iOS was smart enough to shift the control automatically. Of course, iOS isn’t that smart, so developers need to determine exactly what is shifted.

For example, you might have a form with a toolbar at the top, and the rest of the form occupied with a tabcontrol. The following is an animation of what can happen when you don’t shift the control(s): (click each image to see the animation)

One issue is that you might want the toolbar to remain visible, but the parent of the control (or a parent of that) should be shifted up far enough so that the control is completely clear of the virtual keyboard. The following animations demonstrate this. First for an edit control:

..and for a memo control:

Note from this animation that the caret in the memo appears just above the virtual keyboard, rather than below the bottom of the memo control.

The link following contains a demo that can be used with any Firemonkey mobile project, that takes the drudgery out of having to work out how to move the control(s).

By | 2017-02-16T18:02:36+00:00 October 19, 2013 7:09 pm|Code tips, Uncategorized|35 Comments

About the Author:

35 Comments

  1. Firemonkey - scrollen? - Delphi-PRAXiS November 13, 2013 at 1:33 am - Reply

    […] […]

  2. brent shelton November 15, 2013 at 11:14 pm - Reply

    Thanks for this. I’ve been looking for a good solution! I just discovered your site. Very nice!

  3. Jürgen Bauer November 22, 2013 at 11:38 pm - Reply

    Hello,
    thanks for your sample app for scrolling the focused control element.
    Unfortunately, it does not work correctly when the device is rotated.
    Then the footer disappears and the memo component is moved to far up.
    Maybe you have an idea how to fix this?
    Bye,
    Jürgen

    • admin November 23, 2013 at 7:28 am - Reply

      Thanks for your feedback! I’ll take a look at it and come up with a solution.

  4. Jürgen Bauer November 23, 2013 at 12:42 am - Reply

    Hello,
    I took a look at your source code and think that I have found the reason for the “oversized” scrolling.
    In your function TControlMover.GetFocusedControlOffset(KeyboardRect: TRect) the calculation of the number of pixels to move is not correct and has to be like this:

    Result := (ControlPos.Y + ControlHeight + 2) – (ARect.Bottom – Abs (ARect.Top)) + 21;

    With this correction the scrolling does also function in landscape mode.

    In this context, I came across a strange effect when changing the orientation after (!) editing one field. The whole layout is destroyed and it is not possible any more to edit anything.

    Is this a known Firemonkey bug in XE5 SP1?

    Bye,
    Jürgen

    • admin November 23, 2013 at 7:29 am - Reply

      I haven’t updated the code for XE5 Update 1, which does have known problems as you describe. I’ll take a look into it.

  5. Cpucki December 25, 2013 at 10:31 am - Reply

    Nice example. But how can I write a method to move the control when having a date time picker or a custom picker? Your class should handle those controls too (in IOS).

    • admin December 25, 2013 at 10:40 am - Reply

      I’ll have a look into it.. thanks for your feedback!

  6. Cpucki December 25, 2013 at 10:48 pm - Reply

    Thank you. By the way, I recognized that the controls aren’t moved when the device or the simulator change orientation to landscape.

  7. Andrey January 10, 2014 at 6:29 am - Reply

    Does not work if you open the keyboard. (Delphi XE5 UPD2)

    • admin January 10, 2014 at 10:37 am - Reply

      What does “open the keyboard” mean, and on which platform(s)?

      • Andrey January 10, 2014 at 5:38 pm - Reply

        I meant to display the virtual keyboard.
        If the virtual keyboard is displayed, then all elements of the application disappear.
        Platform Android 4.1.2, the device Samsung Galaxy S2.

      • Andrey January 10, 2014 at 5:57 pm - Reply
  8. Pierre January 28, 2014 at 4:04 am - Reply

    I think I found the problem:

    in FormVirtualKeyboardShown it should be

    FSaveProps.Align := FSaveProps.Control.Align;

    In the original code the alignment of the base objects remained at alNone.

  9. […] Head over and get the full source to the TControlMover component and demo. […]

  10. Patrick Mira Pedrol February 15, 2014 at 11:48 am - Reply

    Hi everybody,

    I have been working with your code, and with suggestions that people post here to correct the problems of your ControlMover class, and I get a definitive code for the class that works in all situations. I share with you for your enjoy.

    I have used too a class TFMXUtil posted in this QC for the solution:
    http://qc.embarcadero.com/wc/qcmain.aspx/qcmain.aspx?d=117598

    The final code here (tested with Delphi XE5 Update 2, IOS 7, iPad Mini):

    unit ControlMover;

    interface

    uses
    FMX.SomeUtil, // modified by Patrick 15/2/2014
    FMX.Forms, FMX.Controls, System.Types, FMX.Types;

    type
    TSaveProperties = record
    Control: TControl;
    Align: TAlignLayout;
    Position: TPointF;
    end;

    TGetMoveControlEvent = procedure(Sender: TObject; FocusedControl: TControl; var MoveControl: TControl) of object;

    TControlMover = class(TObject)
    private
    FForm: TCommonCustomForm;
    FSaveProps: TSaveProperties;
    FVKBounds: TRectF; // modified by Patrick
    FVKVisible: Boolean;
    FOnGetMoveControl: TGetMoveControlEvent;
    procedure DoGetMoveControl;
    function GetFocusedControlOffset(KeyboardRect: TRectF): Single; // modified By Patrick 15/2/2014
    function GetStatusBarHeight: Single;
    function GetViewRect: TRectF;
    function FocusedControl: TControl;
    procedure FormVirtualKeyboardHidden(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
    procedure FormVirtualKeyboardShown(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
    public
    constructor Create(AForm: TCommonCustomForm);
    procedure SlideControl;
    property OnGetMoveControl: TGetMoveControlEvent read FOnGetMoveControl write FOnGetMoveControl;
    end;

    implementation

    uses
    {$IFDEF IOS}
    iOSApi.Foundation, iOSApi.UIKit, FMX.Platform.iOS,
    {$ENDIF}
    System.SysUtils, FMX.Memo;

    { TControlMover }

    constructor TControlMover.Create(AForm: TCommonCustomForm);
    begin
    inherited Create;
    FForm := AForm;
    FForm.OnVirtualKeyboardShown := FormVirtualKeyboardShown;
    FForm.OnVirtualKeyboardHidden := FormVirtualKeyboardHidden;
    end;

    procedure TControlMover.FormVirtualKeyboardHidden(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
    begin
    FVKVisible := False;
    if Assigned(FSaveProps.Control) then
    begin
    FSaveProps.Control.AnimateFloat(‘Position.Y’, FSaveProps.Position.Y, 0.1);
    FSaveProps.Control.Align := FSaveProps.Align;
    end;
    end;

    procedure TControlMover.FormVirtualKeyboardShown(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
    begin
    FVKVisible := True;
    // FVKBounds := Bounds; // commented By Patrick 15/2/2014
    FVKBounds := TFMXUtil.VirtualKeyboardRectToAbsoluteRect(TRectF.Create(Bounds), TForm(FForm)); // modified By Patrick 15/2/2014
    if FocusedControl = nil then
    Exit;
    DoGetMoveControl;
    if Assigned(FSaveProps.Control) then
    begin
    FSaveProps.Align := FSaveProps.Control.Align; // modified by Patrick 15/2/2014
    FSaveProps.Control.Align := TAlignLayout.alNone;
    FSaveProps.Position.Y := FSaveProps.Control.Position.Y;
    SlideControl;
    end;
    end;

    procedure TControlMover.DoGetMoveControl;
    var
    MoveControl: TControl;
    begin
    MoveControl := nil;
    if Assigned(FOnGetMoveControl) then
    FOnGetMoveControl(Self, FocusedControl, MoveControl);
    FSaveProps.Control := MoveControl;
    end;

    function TControlMover.FocusedControl: TControl;
    begin
    Result := nil;
    if Assigned(FForm.Focused) and (FForm.Focused.GetObject is TControl) then
    Result := TControl(FForm.Focused.GetObject);
    end;

    function TControlMover.GetFocusedControlOffset(KeyboardRect: TRectF): Single;
    var
    Control: TControl;
    ControlPos: TPointF;
    ControlHeight: Single;
    Memo: TMemo;
    Caret: TCaret;
    ViewRect: TRectF;
    begin
    Result := 0;
    Control := FocusedControl;
    if Assigned(Control) then
    begin
    ControlPos := Control.LocalToAbsolute(PointF(0, 0));
    ControlHeight := Control.Height;
    if Control is TMemo then
    begin
    Memo := TMemo(Control);
    Caret := Memo.Caret;
    ControlPos.Y := ControlPos.Y + (Caret.Pos.Y – Memo.ViewportPosition.Y);
    ControlHeight := Caret.Size.Height + 4;
    end;

    ViewRect := GetViewRect;
    Result := (ControlPos.Y + ControlHeight + 2)
    // Subtract the keyboard height from the view height to obtain the actual top of the keyboard
    – ((ViewRect.Bottom – ViewRect.Top) – (KeyboardRect.Bottom – KeyboardRect.Top))
    // Add the status bar height
    + GetStatusBarHeight;
    if Result < 0 then
    Result := 0;
    end;
    end;

    function TControlMover.GetStatusBarHeight: Single;
    {$IFDEF IOS}
    begin
    Result := 30; // modified by Patrick 14/02/2014
    {$IFDEF CPUARM} // i.e. on an iOS device
    // if TOSVersion.Check(7, 0) then
    // Result := TUIApplication.wrap(TUIApplication.OCClass.SharedApplication).statusBarFrame.size.height; // commented by Patrick 14/02/2014
    {$ENDIF}
    end;
    {$ELSE}
    begin
    Result := 0;
    end;
    {$ENDIF}

    function TControlMover.GetViewRect: TRectF;
    {$IFDEF IOS}
    var
    ARect: NSRect;
    begin
    ARect := WindowHandleToPlatform(FForm.Handle).View.bounds;
    Result := RectF(ARect.origin.x, ARect.origin.y, ARect.size.width – ARect.origin.x, ARect.size.height – ARect.origin.y);
    end;
    {$ELSE}
    begin
    // TODO – Android
    end;
    {$ENDIF}

    procedure TControlMover.SlideControl;
    begin
    if FVKVisible and Assigned(FSaveProps.Control) then
    FSaveProps.Control.AnimateFloat('Position.Y', FSaveProps.Control.Position.Y – GetFocusedControlOffset(FVKBounds), 0.1);
    end;

    end.

  11. Tristan April 25, 2014 at 6:05 am - Reply

    Some tweaks for Android, it can also now be registered as component and dropped onto a form. It will then automatically assign the form.

    If the form already has any keyboard Shown or Hidden events assigned these are remembered and still triggered.

    Still think GetViewRect for Android could be improved.

    unit ControlMover;

    interface

    uses
    FMX.Forms, FMX.Controls, System.Types, FMX.Types, System.Classes;

    type
    TSaveProperties = record
    Control: TControl;
    Align: TAlignLayout;
    Position: TPointF;
    end;

    TGetMoveControlEvent = procedure(Sender: TObject; FocusedControl: TControl;
    var MoveControl: TControl) of object;

    TControlMover = class(TControl)
    private
    FForm: TCommonCustomForm;
    FSaveProps: TSaveProperties;
    FVKBounds: TRectF;
    FVKVisible: Boolean;
    FOnGetMoveControl: TGetMoveControlEvent;
    FFormVirtualKeyboardShownEvent: TVirtualKeyboardEvent;
    FFormVirtualKeyboardHiddenEvent: TVirtualKeyboardEvent;
    procedure DoGetMoveControl;
    function GetFocusedControlOffset(KeyboardRect: TRectF): Single;
    function GetStatusBarHeight: Single;
    function GetViewRect: TRectF;
    function FocusedControl: TControl;
    procedure FormVirtualKeyboardHidden(Sender: TObject;
    KeyboardVisible: Boolean; const Bounds: TRect);
    procedure FormVirtualKeyboardShown(Sender: TObject;
    KeyboardVisible: Boolean; const Bounds: TRect);
    function GetScreenOrientation: TScreenOrientation;
    function VirtualKeyboardRectToAbsoluteRect(const Rect: TRectF;
    const Scene: IScene): TRectF;
    protected
    procedure SetForm(AForm: TCommonCustomForm);
    public
    constructor Create(AOwner: TComponent); override;
    procedure SlideControl;
    published
    property Form: TCommonCustomForm read FForm;
    property OnGetMoveControl: TGetMoveControlEvent read FOnGetMoveControl
    write FOnGetMoveControl;
    end;

    procedure Register;

    implementation

    uses
    {$IFDEF MSWINDOWS}
    ShellApi, Winapi.Windows, FMX.Forms,
    {$ENDIF}
    {$IFDEF ANDROID}
    FMX.Platform.Android,
    {$ENDIF}
    {$IFDEF IOS}
    iOSapi.UIKit, iOSapi.Foundation, FMX.Platform.iOS,
    {$ENDIF}
    FMX.Platform, System.Math, FMX.Memo;
    { TControlMover }

    function TControlMover.GetScreenOrientation: TScreenOrientation;
    var
    {$IFDEF IOS}
    App: UIApplication;
    {$ELSE}
    ScreenService: IFMXScreenService;
    {$ENDIF}
    begin
    {$IFDEF IOS}
    App := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);

    case App.statusBarOrientation of
    UIInterfaceOrientationPortrait:
    Result := TScreenOrientation.soPortrait;
    UIInterfaceOrientationPortraitUpsideDown:
    Result := TScreenOrientation.soInvertedPortrait;
    UIInterfaceOrientationLandscapeLeft:
    Result := TScreenOrientation.soLandscape;
    UIInterfaceOrientationLandscapeRight:
    Result := TScreenOrientation.soInvertedLandscape;

    else
    {$IFDEF DEBUG}
    raise Exception.Create(‘Screen Orientation unknown’);
    {$ELSE}
    Result := TScreenOrientation.soPortrait;
    {$ENDIF}
    end;
    {$ELSE}
    if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService,
    IInterface(ScreenService)) then
    Result := ScreenService.GetScreenOrientation()
    else
    Result := TScreenOrientation.soPortrait;
    {$ENDIF}
    end;

    function TControlMover.VirtualKeyboardRectToAbsoluteRect
    (const Rect: TRectF; const Scene: IScene): TRectF;
    {$IFDEF IOS}
    var
    ScreenService: IFMXScreenService;
    KeybdHeight: Single;
    RealActualOrientation: TScreenOrientation;
    UIApp: UIApplication;

    function GetRealHeightOfTheKeyboard(const R: TRectF): Single;
    var
    ScreenSize: TPointF;
    CertainlyFound: Boolean;
    begin
    ScreenSize := ScreenService.GetScreenSize();
    CertainlyFound := False;
    Result := 0;

    if RealActualOrientation in [TScreenOrientation.soPortrait,
    TScreenOrientation.soInvertedPortrait] then
    begin
    if ScreenSize.Y = R.Height then
    begin
    Result := R.Width;
    CertainlyFound := True;
    end
    else if ScreenSize.Y = R.Width then
    begin
    Result := R.Height;
    CertainlyFound := True;
    end;
    end
    else
    begin
    if ScreenSize.X = R.Height then
    begin
    Result := R.Width;
    CertainlyFound := True;
    end
    else if ScreenSize.X = R.Width then
    begin
    Result := R.Height;
    CertainlyFound := True;
    end;
    end;

    if not CertainlyFound then
    Result := Min(R.Height, R.Width);
    end;
    {$ENDIF}

    begin
    {$IFDEF IOS}
    Result := Rect;
    RealActualOrientation := GetScreenOrientation();

    if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService,
    IInterface(ScreenService)) then
    begin
    // Bug no iOS? Quando o dispositivo está em landscape, ele não informa a
    // posição vertical do teclado virtual corretamente;
    KeybdHeight := GetRealHeightOfTheKeyboard(Result);

    if RealActualOrientation in [TScreenOrientation.soPortrait,
    TScreenOrientation.soInvertedPortrait] then
    Result.Bottom := ScreenService.GetScreenSize.Y
    else
    Result.Bottom := ScreenService.GetScreenSize.X;

    Result.Top := Result.Bottom – KeybdHeight;
    end;

    UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);

    if RealActualOrientation in [TScreenOrientation.soLandscape,
    TScreenOrientation.soInvertedLandscape] then
    Result.Offset(0, -UIApp.statusBarFrame.size.Width)
    else
    Result.Offset(0, -UIApp.statusBarFrame.size.Height);

    {$ELSE}
    Result.TopLeft := Scene.ScreenToLocal(Rect.TopLeft);
    Result.BottomRight := Scene.ScreenToLocal(Rect.BottomRight);
    {$ENDIF}
    end;

    constructor TControlMover.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    FFormVirtualKeyboardShownEvent := nil;
    FFormVirtualKeyboardHiddenEvent := nil;
    if (AOwner is TCommonCustomForm) then
    begin
    SetForm((AOwner as TCommonCustomForm));
    end;
    end;

    procedure TControlMover.SetForm(AForm: TCommonCustomForm);
    begin
    if Assigned(FForm) then
    begin
    FForm.OnVirtualKeyboardShown := FFormVirtualKeyboardShownEvent;
    FForm.OnVirtualKeyboardHidden := FFormVirtualKeyboardHiddenEvent;
    end;

    if Assigned(AForm) then
    begin
    FForm := AForm;
    FFormVirtualKeyboardShownEvent := FForm.OnVirtualKeyboardShown;
    FFormVirtualKeyboardHiddenEvent := FForm.OnVirtualKeyboardHidden;
    FForm.OnVirtualKeyboardShown := FormVirtualKeyboardShown;
    FForm.OnVirtualKeyboardHidden := FormVirtualKeyboardHidden;
    end
    else
    begin
    FForm := nil;
    end;
    end;

    procedure TControlMover.FormVirtualKeyboardHidden(Sender: TObject;
    KeyboardVisible: Boolean; const Bounds: TRect);
    begin
    FVKVisible := False;
    if Assigned(FSaveProps.Control) then
    begin
    FSaveProps.Control.AnimateFloat(‘Position.Y’, FSaveProps.Position.Y, 0.1);
    FSaveProps.Control.Align := FSaveProps.Align;
    end;
    if Assigned(FFormVirtualKeyboardHiddenEvent) then
    begin
    FFormVirtualKeyboardHiddenEvent(Sender, KeyboardVisible, Bounds);
    end;
    end;

    procedure TControlMover.FormVirtualKeyboardShown(Sender: TObject;
    KeyboardVisible: Boolean; const Bounds: TRect);
    begin
    FVKVisible := True;
    FVKBounds := VirtualKeyboardRectToAbsoluteRect(TRectF.Create(Bounds),
    TForm(FForm));
    if FocusedControl = nil then
    Exit;
    DoGetMoveControl;
    if Assigned(FSaveProps.Control) then
    begin
    FSaveProps.Align := FSaveProps.Control.Align;
    FSaveProps.Control.Align := TAlignLayout.None;
    FSaveProps.Position.Y := FSaveProps.Control.Position.Y;
    SlideControl;
    end;
    if Assigned(FFormVirtualKeyboardShownEvent) then
    begin
    FFormVirtualKeyboardShownEvent(Sender, KeyboardVisible, Bounds);
    end;
    end;

    procedure TControlMover.DoGetMoveControl;
    var
    MoveControl: TControl;
    begin
    MoveControl := nil;
    if Assigned(FOnGetMoveControl) then
    FOnGetMoveControl(Self, FocusedControl, MoveControl);
    FSaveProps.Control := MoveControl;
    end;

    function TControlMover.FocusedControl: TControl;
    begin
    Result := nil;
    if Assigned(FForm.Focused) and (FForm.Focused.GetObject is TControl) then
    Result := TControl(FForm.Focused.GetObject);
    end;

    function TControlMover.GetFocusedControlOffset
    (KeyboardRect: TRectF): Single;
    var
    Control: TControl;
    ControlPos: TPointF;
    ControlHeight: Single;
    Memo: TMemo;
    Caret: TCaret;
    ViewRect: TRectF;
    begin
    Result := 0;
    Control := FocusedControl;
    if Assigned(Control) then
    begin
    ControlPos := Control.LocalToAbsolute(PointF(0, 0));
    ControlHeight := Control.Height;
    if Control is TMemo then
    begin
    Memo := TMemo(Control);
    Caret := Memo.Caret;
    ControlPos.Y := ControlPos.Y + (Caret.Pos.Y – Memo.ViewportPosition.Y);
    ControlHeight := Caret.size.Height + 4;
    end;
    ViewRect := GetViewRect;
    Result := (ControlPos.Y + ControlHeight + 2)
    // Subtract the keyboard height from the view height to obtain the actual top of the keyboard
    – ((ViewRect.Bottom – ViewRect.Top) – (KeyboardRect.Bottom –
    KeyboardRect.Top))
    // Add the status bar height
    + GetStatusBarHeight;
    if Result < 0 then
    Result := 0;
    end;
    end;

    function TControlMover.GetStatusBarHeight: Single;
    {$IFDEF IOS}
    begin
    Result := 30; // modified by Patrick 14/02/2014
    {$IFDEF CPUARM} // i.e. on an iOS device
    // if TOSVersion.Check(7, 0) then
    // Result := TUIApplication.wrap(TUIApplication.OCClass.SharedApplication).statusBarFrame.size.height; // commented by Patrick 14/02/2014
    {$ENDIF}
    end;
    {$ELSE}

    begin
    Result := 0;
    end;
    {$ENDIF}

    function TControlMover.GetViewRect: TRectF;
    {$IFDEF IOS}
    var
    ARect: NSRect;
    begin
    ARect := WindowHandleToPlatform(FForm.Handle).View.Bounds;
    Result := RectF(ARect.origin.X, ARect.origin.Y,
    ARect.size.Width – ARect.origin.X, ARect.size.Height – ARect.origin.Y);
    end;
    {$ELSE}
    {$IFDEF ANDROID}

    begin
    Result := WindowHandleToPlatform(FForm.Handle).Bounds;
    end;
    {$ELSE}

    begin
    // Nothing
    end;
    {$ENDIF ANDROID}
    {$ENDIF IOS}

    procedure TControlMover.SlideControl;
    begin
    if FVKVisible and Assigned(FSaveProps.Control) then
    FSaveProps.Control.AnimateFloat('Position.Y', FSaveProps.Control.Position.Y
    – GetFocusedControlOffset(FVKBounds), 0.1);
    end;

    procedure Register;
    begin
    RegisterComponents('Form Helpers', [TControlMover]);
    end;

    end.

    • admin October 19, 2014 at 6:23 pm - Reply

      Hi Tristan,

      Before I jump headlong into debugging this for XE7, have you tried your code with it? In the simulator, when I select the edit in the config page in my demo, the controls slide up, then slide down again (obscured by the VK)

      Thanks!

      • Tristan Marlow October 19, 2014 at 10:42 pm - Reply

        No, I am yet to try XE7, current apps work ok in XE6 waiting for next round of modification before I upgrade.

        • admin October 20, 2014 at 6:40 am - Reply

          OK, I’ll have a play around with it, soon

  12. Reza May 15, 2014 at 10:13 pm - Reply

    Hi

    I have used your code, and your project in Delphi XE6, but the problem is in config page when you click on the the bottom editbox, the list will go up for a moment and then it will get back down under the keyboard.

    • admin June 4, 2014 at 7:55 am - Reply

      I’ll have to re-check this in XE6.

      • admin October 20, 2014 at 9:03 pm - Reply

        It seems to be an issue with TVertScrollbox; it isn’t allowing child objects to have a negative value for Position.Y (at least in XE7, and I guess XE6). I’m looking into it, however anyone shedding any light on this would be welcome.

  13. Aurelio May 29, 2014 at 1:27 am - Reply

    On my iPad “Patrick Mira Pedrol” source code, but and for ANDROID? I need that and i can´t find anywhere! Please, can somebody help me?

    Thanks!

    • admin June 4, 2014 at 7:57 am - Reply

      I’ll have a look into the Android issue; thanks.

  14. B-TGS July 2, 2014 at 5:33 am - Reply

    has anyone made a component for this issue?

  15. admin October 14, 2014 at 6:26 pm - Reply

    Those seeking a solution for Android should check out the Android related comments. I’m about to check out the new features in XE7, and revisit some articles, so there might be some updates to the solutions I’ve provided so far

  16. Thierry MICHEL December 2, 2014 at 9:02 am - Reply

    Hi and thanks for this work. Have you got now a final solution for both Android & IOS for Delphi XE7 ?

    • admin January 23, 2015 at 7:28 pm - Reply

      I’ll check the status of the bug that is preventing it from working in XE6 and XE7. It’s one of those that is a bit difficult to track down.

  17. Leandro May 8, 2015 at 12:43 am - Reply

    There is this code somewhere pro xe8?

    • admin May 8, 2015 at 11:23 am - Reply

      I need to revisit this project for XE8. There’s also a long outstanding bug in TVertScrollBox (possibly since XE6) that I need to resolve, i.e. it does not allow child objects to have a negative value for Position.Y (which worked in XE5)

      I’ll get to it within the next day or so, because it will affect a couple of current projects.

  18. Malcolm August 24, 2015 at 9:30 am - Reply

    Can I take it that there is no progress on this yet?
    It is affecting an Android app of mine and has forced me to restrict input fields, to the upper half of the display.
    Does EMB know about the matter? I fear it will still be unfixed in XE9.

  19. […] Malcolm on Moving controls into view when the virtual keyboard is shown […]

Leave a Reply

Show Buttons
Hide Buttons