FMX + Android + 旋转

FMX + Android + Rotation

尝试确定“180° 翻转”:all of the above methods 当设备快速翻转时(例如从“横向”到“反向横向”)毫无用处

但是有一种“原生方式”——通过OrientationEventListener。谁能帮助实现它?

unit android.view.OrientationEventListener;

interface

uses
  AndroidAPI.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText;

type
  JOrientationEventListener = interface;

  JOrientationEventListenerClass = interface(JObjectClass)
    ['{6C04CBB1-63B1-45E1-9CBE-AE3F41A60064}']
    function _GetORIENTATION_UNKNOWN: Integer; cdecl;
    function canDetectOrientation : boolean; cdecl;
    function init(context: JContext): JOrientationEventListener; cdecl; overload;
    function init(context: JContext; rate: Integer): JOrientationEventListener; cdecl; overload;
    procedure disable; cdecl;
    procedure enable; cdecl;
    procedure onOrientationChanged(Integerparam0: integer); cdecl;
    property ORIENTATION_UNKNOWN : Integer read _GetORIENTATION_UNKNOWN;
  end;

  [JavaSignature('android/view/OrientationEventListener')]
  JOrientationEventListener = interface(JObject)
    ['{ED4F435E-E48F-420E-A26E-75BFB8FCCB94}']
    function canDetectOrientation: boolean; cdecl;
    procedure disable; cdecl;
    procedure enable; cdecl;
    procedure onOrientationChanged(Integerparam0: integer); cdecl;
  end;

  TJOrientationEventListener = class(TJavaGenericImport<JOrientationEventListenerClass, JOrientationEventListener>)
  end;

const
  TJOrientationEventListenerORIENTATION_UNKNOWN = -1;

implementation

end.

我开始考虑创建 OrientationEventListener 的后代(目前只能在 Java 代码中完成),但是它有自己的一系列问题,即 canDetectOrientation 函数会总是 return 错误!

接下来我研究了为什么 activity 没有调用 TOrientationChangedMessage was not being sent when changing immediately from "normal" to "inverted" orientation - that appears to be because the onConfigurationChanged 方法(即 Delphi 无法解决这个问题)

然后我想也许最简单的方法是使用计时器 (ugh) 来检查屏幕旋转何时发生变化,所以我想出了以下 unit which is now in the Kastri repo:

unit DW.OrientationMonitor;

{*******************************************************}
{                                                       }
{                      Kastri                           }
{                                                       }
{         Delphi Worlds Cross-Platform Library          }
{                                                       }
{  Copyright 2020-2021 Dave Nottage under MIT license   }
{  which is located in the root folder of this library  }
{                                                       }
{*******************************************************}

{$I DW.GlobalDefines.inc}

interface

uses
  // FMX
  FMX.Types;

type
  TOrientationChangedEvent = procedure(Sender: TObject; const Orientation: TScreenOrientation) of object;

  TOrientationMonitor = class(TObject)
  private
    FHasOrientationChanged: Boolean;
    FOrientation: TScreenOrientation;
    FRotation: Integer;
    FTimer: TTimer;
    FOnOrientationChanged: TOrientationChangedEvent;
    procedure DoOrientationChange;
    procedure SetIsActive(const Value: Boolean);
    procedure TimerHandler(Sender: TObject);
    function GetIsActive: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
    property IsActive: Boolean read GetIsActive write SetIsActive;
    property Orientation: TScreenOrientation read FOrientation;
    property OnOrientationChanged: TOrientationChangedEvent read FOnOrientationChanged write FOnOrientationChanged;
  end;

implementation

uses
  // DW
  DW.UIHelper;

{ TOrientationMonitor }

constructor TOrientationMonitor.Create;
begin
  inherited;
  FOrientation := TUIHelper.GetScreenOrientation;
  FTimer := TTimer.Create(nil);
  FTimer.Interval := 100;
  FTimer.OnTimer := TimerHandler;
end;

destructor TOrientationMonitor.Destroy;
begin
  FTimer.Free;
  inherited;
end;

procedure TOrientationMonitor.DoOrientationChange;
begin
  if Assigned(FOnOrientationChanged) then
    FOnOrientationChanged(Self, FOrientation);
end;

function TOrientationMonitor.GetIsActive: Boolean;
begin
  Result := FTimer.Enabled;
end;

procedure TOrientationMonitor.SetIsActive(const Value: Boolean);
begin
  FTimer.Enabled := Value;
end;

procedure TOrientationMonitor.TimerHandler(Sender: TObject);
var
  LOrientation: TScreenOrientation;
begin
  LOrientation := TUIHelper.GetScreenOrientation;
  if LOrientation <> FOrientation then
  begin
    FOrientation := LOrientation;
    DoOrientationChange;
  end;
end;

end.

注意 该单元依赖于 Kastri 存储库中的其他单元,但您也可以提取 GetScreenOrientation 方法

使用TOrientationMonitor的例子:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls,
  DW.OrientationMonitor;

type
  TForm1 = class(TForm)
    Label1: TLabel;
  private
    FOrientation: TScreenOrientation;
    FOrientationMonitor: TOrientationMonitor;
    procedure OrientationChangedHandler(Sender: TObject; const AOrientation: TScreenOrientation);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses
  System.TypInfo;

{ TForm1 }

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited;
  FOrientationMonitor := TOrientationMonitor.Create;
  FOrientationMonitor.OnOrientationChanged := OrientationChangedHandler;
  FOrientation := FOrientationMonitor.Orientation;
  Label1.Text := Format('Orientation: %s', [GetEnumName(TypeInfo(TScreenOrientation), Ord(FOrientation))]);
  FOrientationMonitor.IsActive := True;
end;

destructor TForm1.Destroy;
begin
  FOrientationMonitor.Free;
  inherited;
end;

procedure TForm1.OrientationChangedHandler(Sender: TObject; const AOrientation: TScreenOrientation);
var
  LInfo: PTypeInfo;
begin
  LInfo := TypeInfo(TScreenOrientation);
  Label1.Text := Format('Old: %s, New: %s', [GetEnumName(LInfo, Ord(FOrientation)), GetEnumName(LInfo, Ord(AOrientation))]);
  FOrientation := AOrientation;
end;

end.

在这次调查中,我发现测试应用程序不会旋转到倒立的纵向位置。实现它的技巧是更新清单,将值为 fullSensorandroid:screenOrientation 属性包含到 activity 节点中,如下所示:

<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
        android:label="%activityLabel%"
        android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
        android:screenOrientation="fullSensor"
        android:launchMode="singleTask">

我知道这并不能完全回答您关于 OrientationEventListener 的问题,但我希望它能实现您的期望