NOTE: Google translator it's horrible ok!!!
Scenary:
a) Delphi 13.1
b)
Android 16 ( API 36 ) - using Android Simulator by Google
1) in fact, the solutions already exists in Delphi 13.x using "Form.... SafeAreaChanged" event:
a) use a "container" ( like TLayout, TPanel, etc... ) to accomodate your visual components, define the "Align" property to "Client"
b) in "SafeAreaChanged" from Form, just re-define the 4 "Padding" properties
procedure TForm1.FormSafeAreaChanged( Sender: TObject; const AInsets: TRectF );
begin
Padding.Top := AInsets.Top;
Padding.Left := AInsets.Left;
Padding.Right := AInsets.Right;
Padding.Bottom := AInsets.Bottom;
//
// visual tests...
Memo1.Text := Format( 'NL=%f, NT=%f, NR=%f, NB=%f', //
[ AInsets.Left, AInsets.Top, AInsets.Right, AInsets.Bottom ] );
end;
To demonstrate that the event is working correctly, you could switch the Android theme and observe the margins being respected.
The TForm uses "Fill.Kind = SOLID" to correctly render the Android theme, but this is not required for rotation or form margin management.
Additionally, there is a native Android API call that utilizes the "OnLayoutChange" event (which Embarcadero likely uses for the SafeAreaChanged event).
This event is part of the Android callback system; it offers greater control—being essential for class and system-level registration—and provides additional functionality.
The form's "SafeAreaChanged" event is the most practical and straightforward option, given the form class!
procedure TWindowLayoutChangeListener.onLayoutChange( V: JView; left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom: Integer );
var
LInsets : JWindowInsets;
LLeftInset, LTopInset, LRightInset, LBottomInset: Single;
LNewLeft, LNewTop, LNewRight, LNewBottom : Single;
LScreenScale : Single;
begin
if Assigned( V ) and Assigned( FForm ) then
begin
LInsets := V.getRootWindowInsets;
//
if Assigned( LInsets ) then
begin
// To illustrate the concepts, I am using many variables, but this isn't strictly necessary! Just be sure to watch out for division by zero!
//
// Now, based on the device's current scale, you will be able to calculate the new values...
// LScreenScale := TAndroidHelper.Activity.getResources.getDisplayMetrics.density;
LScreenScale := GetScreenScale;
//
if LScreenScale = 0 then
LScreenScale := 1;
//
LTopInset := LInsets.getSystemWindowInsetTop;
LLeftInset := LInsets.getSystemWindowInsetLeft;
LRightInset := LInsets.getSystemWindowInsetRight;
LBottomInset := LInsets.getSystemWindowInsetBottom;
//
// TForm olmadan doğrudan uygulama veya dolgu
LNewTop := LTopInset / LScreenScale;
LNewLeft := LLeftInset / LScreenScale;
LNewRight := LRightInset / LScreenScale;
LNewBottom := LBottomInset / LScreenScale;
//
FForm.Padding.top := LNewTop;
FForm.Padding.left := LNewLeft;
FForm.Padding.right := LNewRight;
FForm.Padding.bottom := LNewBottom;
//
// Form_InsetsListener is my Form main...
Form_InsetsListener.Memo1.Lines.Add( 'Scale=' + LScreenScale.ToString );
Form_InsetsListener.Memo1.Lines.Add( //
Format( 'LI=%f, TI=%f, RI=%f, BI=%f', [ LLeftInset, LTopInset, LRightInset, LBottomInset ] ) );
Form_InsetsListener.Memo1.Lines.Add( //
Format( 'NL=%f, NT=%f, NR=%f, NB=%f', [ LNewLeft, LNewTop, LNewRight, LNewBottom ] ) );
end
else
Form_InsetsListener.Memo1.Lines.Add( 'LInsets is NIL' );
end
else
Form_InsetsListener.Memo1.Lines.Add( '"V" is NIL' );
end;