Delphi iOSアプリケーションでネイティブコントロールの上に画像を表示する

FireMonkeyのコントロールはネイティブコントロールの上に表示することができません。

Delphi iOSアプリケーションでネイティブコントロールの上に画像を表示するために
ネイティブコントロールのUIImageViewをラップしたクラスを作成しました。

UIImageViewもネイティブコントロールのため、ネイティブコントロールの上に画像を表示できます。

使用例

FUIImageView := FMX.iOS.UIImageView.TUIImageView.Create(Layout1);
FUIImageView.ImageWrapMode := TImageWrapMode.Fit;
FUIImageView.SetBitmap(Bitmap);

ソースコード

unit FMX.iOS.UIImageView;

interface

uses
  iOSapi.UIKit, iOSapi.CoreGraphics,
  System.Classes, System.Types, FMX.Graphics,
  FMX.Layouts, FMX.Forms, FMX.Objects;

type
  TUIImageView = class
  private
    FUIImageView: iOSapi.UIKit.UIImageView;
    FLayout: TLayout;
    FImageWrapMode: TImageWrapMode;
    procedure SetImageWrapMode(const Value: TImageWrapMode);
    function GetForm: TCustomForm;
    function GetLayoutRect: TRect;
    function getFrame: CGRect;
  public
    constructor Create(const ALayout: TLayout);
    destructor Destroy; override;
    procedure SetBitmap(const ABitmap: TBitmap);
    procedure Resize;
    property ImageWrapMode: TImageWrapMode read FImageWrapMode
      write SetImageWrapMode;
    property frame: CGRect read getFrame;
    property ImageView: iOSapi.UIKit.UIImageView read FUIImageView;

  end;

implementation

uses

  Macapi.Helpers, FMX.Helpers.iOS, iOSapi.Foundation, FMX.Platform.iOS,

  System.SysUtils, FMX.Types;

{ TUIImageView }

constructor TUIImageView.Create(const ALayout: TLayout);
var
  AForm: TCustomForm;
begin
  FLayout := ALayout;

  FUIImageView := iOSapi.UIKit.TUIImageView.Wrap
    (iOSapi.UIKit.TUIImageView.Alloc.init);
  FUIImageView.retain;
  Resize;

  AForm := GetForm;
  if AForm <> nil then
    WindowHandleToPlatform(AForm.Handle).View.addSubview(FUIImageView);

  Self.ImageWrapMode := TImageWrapMode.Stretch;
end;

destructor TUIImageView.Destroy;
begin
  if FUIImageView <> nil then
  begin
    FUIImageView.removeFromSuperview;
    FUIImageView.release;
    FUIImageView := nil;
  end;

  inherited;
end;

function TUIImageView.GetForm: TCustomForm;
var
  Parent: TFmxObject;
begin
  Parent := FLayout.Parent;

  while True do
  begin
    if Parent = nil then
      Exit(nil);
    if Parent is TForm then
      Exit(Parent as TForm);
    Parent := Parent.Parent;
  end;
end;

function TUIImageView.getFrame: CGRect;
begin
  Result := FUIImageView.frame;
end;

function TUIImageView.GetLayoutRect: TRect;
var
  ATopLeft, ABottomRight: TPoint;
begin
  if FLayout = nil then
  begin
    Log.d('Layout = nil');
    Exit(Rect(0, 0, 0, 0));
  end;

  ATopLeft := FLayout.LocalToAbsolute(PointF(0, 0)).Truncate;
  ABottomRight := ATopLeft.Add(PointF(FLayout.width, FLayout.height).Truncate);
  Result := System.Classes.Rect(ATopLeft, ABottomRight);
end;

procedure TUIImageView.Resize;
begin
  FUIImageView.setFrame(Macapi.Helpers.RectToNSRect(GetLayoutRect));
end;

procedure TUIImageView.SetBitmap(const ABitmap: TBitmap);
var
  Image: UIImage;
  AutoreleasePool: NSAutoreleasePool;
begin
  AutoreleasePool := TNSAutoreleasePool.Create;
  try
    Image := FMX.Helpers.iOS.BitmapToUIImage(ABitmap);
    FUIImageView.setImage(Image);
  finally
    AutoreleasePool.release
  end;
end;

procedure TUIImageView.SetImageWrapMode(const Value: TImageWrapMode);
begin
  FImageWrapMode := Value;

  case Value of
    TImageWrapMode.Fit: // コントロールの四角形にちょうど合うように調整します(画像の比率は保たれます)。
      FUIImageView.setContentMode(UIViewContentModeScaleAspectFit);
    TImageWrapMode.Stretch: // 画像を引き伸ばして、コントロールの四角形全体を埋めます。
      FUIImageView.setContentMode(UIViewContentModeScaleToFill);
    TImageWrapMode.Original: // 画像を元のサイズで表示します。
      FUIImageView.setContentMode(UIViewContentModeTopLeft);
    TImageWrapMode.Center: // 画像をコントロールの四角形の中央に表示します。
      FUIImageView.setContentMode(UIViewContentModeCenter);
    TImageWrapMode.Tile: // 画像を敷き詰めて(画像の数を増やして)、コントロールの四角形全体を覆います。
      raise System.SysUtils.ENotImplemented.Create('TImageWrapMode.Tile');
  end;
end;

end.

サンプルプログラム

TWebBrowserコントロールはネイティブコントロールのため、その上にコンポーネントを配置できません。

このサンプルプログラムでは、TWebBrowserコントロールの上にTUIImageViewを配置して、画像を表示します。

実行例は次のようになります。

Simulator Screen Shot 2016.06.20 0.30.50

フォームにTWebBrowserコントロールとTLayoutコントロールを配置します。
TLayoutコントロールはTUIImageViewの配置場所になります。

TUIImageView01

TUIImageView02

メニューの「プロジェクト」→「リソースと画像」を選択し、表示する画像を追加します。

TUIImageView03

今回使用した画像は次の画像です。

sample

画像を読み込む関数を作成します。

function GetImage: TBitmap;
var
  RS: TResourceStream;
begin
  Result := TBitmap.Create;
  RS := TResourceStream.Create(HInstance, 'PngImage_1', RT_RCDATA);
  try
    Result.LoadFromStream(RS);
  finally
    RS.Free;
  end;
end;

フォームにprivate変数にTUIImageViewを追加します。

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Layout1: TLayout;
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
    FUIImageView: TUIImageView;
  public
    { public 宣言 }
  end;

フォームのOnCreateイベントで、TWebBrowserコントロールにURLを指定してアクセスします。

procedure TForm1.FormCreate(Sender: TObject);
begin
  WebBrowser1.Navigate('http://www.gesource.jp/weblog/');
end;

フォームのOnCreateイベントにTUIImageViewを作成する処理を追加します。

uses
  FMX.Objects;

procedure TForm1.FormCreate(Sender: TObject);
var
  Bitmap: TBitmap;
begin
  WebBrowser1.Navigate('http://www.gesource.jp/weblog/');

  FUIImageView := FMX.iOS.UIImageView.TUIImageView.Create(Layout1);
  FUIImageView.ImageWrapMode := TImageWrapMode.Fit;

  Bitmap := GetImage;
  try
    FUIImageView.SetBitmap(Bitmap);
  finally
    Bitmap.Free;
  end;
end;

アプリケーションを実行すると、ブラウザの上に画像が表示されます。

Simulator Screen Shot 2016.06.20 0.30.50

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください