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 )
