4

We are starting to port one of our existing iOS (XCode) apps to Delphi FireMonkey (XE4). So far it has been a surprisingly smooth process. However, we have hit a dead end that we have no idea how to solve.

Our existing app is similar to the new Google Maps app. We have a webbrowser control that displays a Google Map containing a number of pins. We also have a settings button and an info panel that appears when a pin is cicked. The settings and info panels slide in from the left and right over the map when the appropriate button/pin is pressed. This all works fine in the XCode app.

Here are the issues we are having with the FireMonkey port:

  • We cannot display a FireMonkey control over the top of the webbrowser control. I understand that this is because the webbroswer is a native iOS control.
  • Once the webbrowser control appears it cannot be moved e.g. if we change the position.x property, the webbrowser stays where it is. This is the same if we change to x property using a built in animation. The only property that seems to work correctly is visible.

Using the TMS iCL components we are able to correct the first issue. However, the most worrisome problem for us is the second. Without being able to move the webbrowser component it is impossible to implement a modern looking (sliding) UI that uses a webbrowser (or any native iOS control).

Has anybody come across a way to overcome these FireMonkey limitations?

UPDATE 1

As per Jaroslav's suggestion I tried the following:

1) Created a second form with a button and a WebBrowser.

unit Unit2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
  FMX.StdCtrls, FMX.WebBrowser;

type
  TForm2 = class(TForm)
    WebBrowser1: TWebBrowser;
    Button1: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.fmx}

end.

2) Created the Form2 as child of Form1.

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls, FMX.WebBrowser,

  Unit2;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FForm2: TForm2;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Fform2.left := Fform2.left - 5;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Fform2.left := Fform2.left + 5;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FForm2 := TForm2.Create(Self);
  FForm2.Parent := Self;
  FForm2.Left := 10;
  FForm2.Show;
  FForm2.BringToFront;
  FForm2.WebBrowser1.URL := 'www.google.com';
  FForm2.WebBrowser1.Navigate;
end;

end.

When I run the application I see this:

enter image description here

Here are my observations:

  • Clicking the buttons has no effect.
  • The button on Form2 is not visible.
  • Form2's Left property is set to 40 in the designer. However, the form is displayed at 0.

Update 2:

Following the suggestions in the comments I changed the Form1 source to:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls, FMX.WebBrowser,

  Unit2;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    Popup1: TPopup;
    WebBrowser1: TWebBrowser;
    WebBrowser2: TWebBrowser;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FForm2: TForm2;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  TCustomForm(Popup1.Popupform).Left := TCustomForm(Popup1.Popupform).Left - 5;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  TCustomForm(Popup1.Popupform).Left := TCustomForm(Popup1.Popupform).Left + 5;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  WebBrowser1.URL := 'www.google.com';
  WebBrowser1.Navigate;
  Popup1.Popup(FALSE);
end;

end.

Unfortunately, neither the movement nor the overlay works. The current code throws an exception when referencing TCustomForm(Popup1.Popupform).Left. The reason the exception occurs is that Delphi closes the popup (destroying the popup form) as soon as a left mouse down event happens on the parent form. What's even stranger is that the popup with the webbrowser is still visible after it is supposed to have closed even though it doesn't react when clicked.

Changing the code to Popup1.Position.X doesn't throw an exception, but of course the popup still doesn't move.

In addition, the label that is parented to the popup is still shown under the webbrowser that is owned by the main form.

Update 3

I have found a number of issues, but fixing them doesn't make it work any better.

  1. For some (inexplicable) reason, it seems that cutting a control (CTRL-X), then selecting another control and pasting (CTRL-V) pastes the cut control to the main form, not the selected control. The only way to reparent a control is to drag and drop it in the Structure tree.
  2. After reparenting the controls to the PopUp, I now get an exception as soon as I call Popup1.Popup(FALSE). This is most likely because the popup is being displayed in the Create event. Moving it to an OnClick event gets rid of the exception.
  3. It seems that in order to stop a popup closing when the main form is clicked you should set the StaysOpen property before calling .Popup, In reality however, this property doesn't seem to work correctly. For example, the following code makes it to the TCustomForm(Popup1.PopupForm).Left line, but then throws an exception as the popup form has already been destroyed!

Code:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Popup1.StaysOpen := TRUE;
  Popup1.Popup(FALSE);

  if Popup1.HasPopupForm then
    TCustomForm(Popup1.PopupForm).Left := TCustomForm(Popup1.PopupForm).Left - 5;
end;
norgepaul
  • 5,775
  • 3
  • 40
  • 68

1 Answers1

2

For solution we should know:

  1. Each Firemonkey form bases on Native UIView, which is subview by root view in Main UIViewController. So when you insert control on a FireMonkey form, that control stay on Form's UIView.
  2. All standart Firemonkey Controls doesn't have Native UIView. FMX form have all FMX controls and manages them.
  3. Firemonkey WebBrowser bases on UIWebView and is displayed like a subview in a Firemonkey form's UIView.
  4. All Popup form are based on UIView with transparent background. Position of popup and size set throught properties TForm.Position, TForm.Size. So you can create a form with transparent background above on Form with TWebBrowser, set size and set position.

For the solution of your problem you can:

  1. Create new form or popup form
  2. Set size and position for it.
  3. Show it from form with WebBrowser. In this case new form will be displayed as a separated UIView on a top of all UIView
Yaroslav Brovin
  • 935
  • 6
  • 19
  • +Yaroslav Brown - I tried your suggestion. See the update above for my findings. – norgepaul Aug 02 '13 at 20:46
  • Ok. I See. 1. Add TPopup on Form 2. Add any control in TPopup 3. Invoke Popup1.Popup; For me popup is appeared above WebBrowser – Yaroslav Brovin Aug 05 '13 at 15:15
  • I can't try this right now, but... are you saying that a) adding controls to a popup will allow them to be displayed over a native iOS control and b) a popup that contains a native control can be moved in the same way a FireMonkey control. Is the Popup not displayed modally in iOS? – norgepaul Aug 06 '13 at 08:17
  • Yes. You are right. The main feature, that popup use TopMost property and set it in true. So our form (PopupForm) displayed on top of all UIView. Try to set TopMost property in true for you. – Yaroslav Brovin Aug 06 '13 at 08:58
  • But can the popup be moved? Is it modal i.e. can the user interact with the controls under the popup? – norgepaul Aug 06 '13 at 09:04
  • Yes. Popup can be moved. (look at TPopup.PopupForm. you should cast it at TCustomForm class) If you look at source code of popup, you will discover, that Popup use simple form with set predefined property. You can use form (as i suggest in first way, but in addition you need to set TopMost in True) IN this case, form will not close and it must to transfer event from outside to back form. Unfortunately, we already has new version of Popup and it's version works fine in your case and other. – Yaroslav Brovin Aug 06 '13 at 09:16
  • Popu can be moved, if you get popup form and will change position – Yaroslav Brovin Aug 06 '13 at 09:19
  • Sorry, your suggestions don't seem to work. See Update 2 in the original question for more information. Any chance you can post some working source? – norgepaul Aug 06 '13 at 14:35