FMXTAniCalculations (Delphi)
Contents
Description
This example shows how to use the Animation, DecelerationRate, BoundsAnimation, AutoShowing, and Shown properties to set the inertial scrolling properties for the TScrollBox scroll component. By setting these scrolling properties, you can customize the behavior of the inertial moving of a scroll view in response to a touch input (with the mouse or finger).
In the TScrollBox class, the AniCalculations property handles the TAniCalculations type object that provides support for the smooth inertial scrolling. Since AniCalculations has public (not published) visibility, you cannot set the scrolling properties in the Object Inspector. You can set the inertial scrolling properties of the AniCalculations object programmatically. For example, using the properties of AniCalculations, you can emulate smooth inertial moving of a scroll view under Windows platforms.
To build and test this example, create a Multi-Device Application - Delphi project and add the following controls on the main form:
- A TRectangle to occupy the most part of the form.
- A TScrollBox into TRectangle to coincide with the TRectangle.
- A TLabel on the upper-left corner of the form.
- Several TButton objects to populate the rectangle of the TScrollBox.
- Short vertical and horizontal TLine objects on the upper-left corner of the form.
- A TText object between two lines on the upper-left corner of the form.
The designed form can look like this:
The corresponding InertialScrolling.FMX file can look like this:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 232 ClientWidth = 332 FormFactor.Width = 320 FormFactor.Height = 480 FormFactor.Devices = [Desktop, Phone, Pad] OnCreate = FormCreate OnShow = FormShow DesignerMobile = False DesignerWidth = 0 DesignerHeight = 0 DesignerDeviceName = '' DesignerOrientation = 0 object Rectangle1: TRectangle Align = Client Height = 200.000000000000000000 Margins.Left = 16.000000000000000000 Margins.Top = 16.000000000000000000 Margins.Right = 16.000000000000000000 Margins.Bottom = 16.000000000000000000 Stroke.Color = claNull Stroke.Dash = Dash Width = 300.000000000000000000 object ScrollBox1: TScrollBox Touch.InteractiveGestures = [Pan] Align = Client ClipChildren = True Height = 200.000000000000000000 TabOrder = 0 Width = 300.000000000000000000 OnPaint = ScrollBox1Paint object Line1: TLine Height = 9.000000000000000000 LineType = Top Position.X = -20.000000000000000000 Width = 40.000000000000000000 end object Line2: TLine Height = 40.000000000000000000 LineType = Left Position.Y = -20.000000000000000000 Width = 9.000000000000000000 end object Text1: TText Color = claBlack Height = 17.000000000000000000 Text = '0, 0' Width = 25.000000000000000000 end object Button1: TButton Height = 22.000000000000000000 Position.X = 56.000000000000000000 Position.Y = 96.000000000000000000 TabOrder = 3 Text = 'Button1' Width = 80.000000000000000000 end object Button2: TButton Height = 22.000000000000000000 Position.X = 8.000000000000000000 Position.Y = 184.000000000000000000 TabOrder = 4 Text = 'Button2' Width = 80.000000000000000000 end end
The example shows the scroll box populated with button controls. The bounding rectangle for all buttons forms the scrolling viewport.
Code
Add the following code into the InertialScrolling.pas file of the form:
unit InertialScrolling;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Graphics,
FMX.StdCtrls, FMX.Objects, FMX.Layouts;
type
TScrollBox = class (FMX.Layouts.TScrollBox)
end;
TForm1 = class(TForm)
Rectangle1: TRectangle;
ScrollBox1: TScrollBox;
Line1: TLine;
Line2: TLine;
Text1: TText;
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure ScrollBox1Paint(Sender: TObject; Canvas: TCanvas;
const ARect: TRectF);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure ViewportPositionChange(Sender: TObject;
const OldViewportPosition, NewViewportPosition: TPointF;
const ContentSizeChanged: Boolean);
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormCreate(Sender: TObject);
begin
// Edit these properties to change inertial scrolling parameters
ScrollBox1.AniCalculations.TouchTracking := [ttVertical, ttHorizontal]; // [ttVertical]; //
ScrollBox1.AniCalculations.Animation := True; // False; //
ScrollBox1.AniCalculations.BoundsAnimation := False; // True; //
ScrollBox1.AniCalculations.DecelerationRate := 0.5; //DecelerationRateFast; //DecelerationRateNormal; //
ScrollBox1.AniCalculations.AutoShowing := True; // False; //
ScrollBox1.OnViewportPositionChange := ViewportPositionChange;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
Invalidate;
end;
procedure TForm1.ScrollBox1Paint(Sender: TObject; Canvas: TCanvas;
const ARect: TRectF);
var
State: TCanvasSaveState;
R, NewR: TRectF;
begin
State := Canvas.SaveState;
try
if Assigned(ScrollBox1.Content) then
begin
NewR := ScrollBox1.ContentLayout.LocalRect;
NewR.TopLeft := ScrollBox1.ContentLayout.LocalToAbsolute(NewR.TopLeft);
NewR.BottomRight := ScrollBox1.ContentLayout.LocalToAbsolute(NewR.BottomRight);
NewR.TopLeft := ScrollBox1.AbsoluteToLocal(NewR.TopLeft);
NewR.BottomRight := ScrollBox1.AbsoluteToLocal(NewR.BottomRight);
InflateRect(NewR, -0.5, -0.5);
Canvas.Stroke.Color := TAlphaColorRec.Black;
Canvas.Stroke.Dash := TStrokeDash.Solid;
Canvas.DrawRect(NewR, 0, 0, AllCorners, 0.5);
R := ScrollBox1.ContentBounds;
NewR.TopLeft := ScrollBox1.Content.LocalToAbsolute(R.TopLeft);
NewR.BottomRight := ScrollBox1.Content.LocalToAbsolute(R.BottomRight);
NewR.TopLeft := ScrollBox1.AbsoluteToLocal(NewR.TopLeft);
NewR.BottomRight := ScrollBox1.AbsoluteToLocal(NewR.BottomRight);
Canvas.Stroke.Color := TAlphaColorRec.Red;
Canvas.DrawRect(NewR, 0, 0, AllCorners, 0.5);
Canvas.Fill.Color := TAlphaColorRec.Red;
Canvas.DrawLine(PointF(NewR.Right, NewR.Top),
PointF(NewR.Right + 4, NewR.Top - 4),
0.5);
NewR.Left := NewR.Right;
Newr.Offset(5, -15);
NewR.Right := NewR.Left + 200;
Canvas.FillText(NewR,
'ContentBounds: ' + #13#10 +
FloatTostr(R.Left) + '; ' +
FloatTostr(R.Top) + '; ' +
FloatTostr(R.Right) + '; ' +
FloatTostr(R.Bottom),
False,
0.5,
[],
TTextAlign.Leading,
TTextAlign.Leading);
NewR.TopLeft := ScrollBox1.ViewportPosition;
NewR.BottomRight := NewR.TopLeft;
NewR.BottomRight.Offset(10, 10);
NewR.TopLeft := ScrollBox1.Content.LocalToAbsolute(NewR.TopLeft);
NewR.BottomRight := ScrollBox1.Content.LocalToAbsolute(NewR.BottomRight);
NewR.TopLeft := ScrollBox1.AbsoluteToLocal(NewR.TopLeft);
NewR.BottomRight := ScrollBox1.AbsoluteToLocal(NewR.BottomRight);
Canvas.Stroke.Color := TAlphaColorRec.Green;
Canvas.DrawLine(NewR.TopLeft, NewR.BottomRight, 0.5);
NewR.TopLeft := NewR.BottomRight;
NewR.BottomRight.Offset(200, 20);
Canvas.Fill.Color := TAlphaColorRec.Green;
Canvas.FillText(NewR,
'ViewportPosition: ' + FloatTostr(ScrollBox1.ViewportPosition.X) + '; ' +
FloatTostr(ScrollBox1.ViewportPosition.Y),
False,
0.5,
[],
TTextAlign.Leading,
TTextAlign.Leading);
end;
finally
Canvas.RestoreState(State);
end;
end;
procedure TForm1.ViewportPositionChange(Sender: TObject;
const OldViewportPosition, NewViewportPosition: TPointF;
const ContentSizeChanged: Boolean);
var
S: string;
begin
S := 'ContentLayout: ' +
FloatTostr(ScrollBox1.ContentLayout.LocalRect.Left) + '; ' +
FloatTostr(ScrollBox1.ContentLayout.LocalRect.Top) + '; ' +
FloatTostr(ScrollBox1.ContentLayout.LocalRect.Right) + '; ' +
FloatTostr(ScrollBox1.ContentLayout.LocalRect.Bottom);
Label1.Text := S;
end;
end.
The following code is the most interesting for us:
procedure TForm1.FormCreate(Sender: TObject); begin // Edit these properties to change inertial scrolling parameters ScrollBox1.AniCalculations.TouchTracking := [ttVertical, ttHorizontal]; // [ttVertical]; // ScrollBox1.AniCalculations.Animation := True; // False; // ScrollBox1.AniCalculations.BoundsAnimation := False; // True; // ScrollBox1.AniCalculations.DecelerationRate := 0.5; //DecelerationRateFast; //DecelerationRateNormal; // ScrollBox1.AniCalculations.AutoShowing := True; // False; //
These properties define parameters of the inertial moving of the scrolling area. Look how the Canvas.FillText method is used to write the ContentBounds
, ViewportPosition
strings and how Label1.Text is used to show the ContentLayout
string.
Build and run the target. The example demonstrates how the form containing the scrollable area looks like:
Use the mouse to change the form size. You can test how the scrollable area inertially scrolls as a response to the mouse movement.
Change the values of the properties used in the TForm1.FormCreate. Build and run the modified target. Compare the modified behavior.
Uses
- FMX.InertialMovement.TAniCalculations ( fr | de | ja )
- FMX.Layouts.TScrollBox ( fr | de | ja )
See Also
InertialMovement.TAniCalculations.Animation ( fr | de | ja )
FMX.InertialMovement.TAniCalculations.DecelerationRate ( fr | de | ja )
FMX.InertialMovement.TAniCalculations.BoundsAnimation ( fr | de | ja )
FMX.InertialMovement.TAniCalculations.AutoShowing ( fr | de | ja )
FMX.InertialMovement.TAniCalculations.Shown ( fr | de | ja )