本增强的目的是解决动画对象只支持 published 的有效的几种属性的问题,确切的说,这是一个适配器,通过匿名函数建立与非 published 属性的适配。我在 [FMX] Delphi 中 TAnimation 设计的几点值得商榷的地方 一文中讨论了 FMX 动画支持类的一些值得商榷的地方和改动,而这个增强从另一个角度来解决问题。
我们直接来看这个单元的全部源码:
unit FMX.AniEh;
// FMX.AniEh is a animation helper for unpublished property,create by QDAC swish and under freebsd license
interface
uses classes, fmx.types;
type
TGetValueProc<T> = reference to procedure(Sender: TObject; var AValue: T);
TSetValueProc<T> = reference to procedure(Sender: TObject; const AValue: T);
TAnimationHelper<T>=class(TFMXObject)
private
FOnSetValue : TSetValueProc<T>;
FOnGetValue:TGetValueProc<T>;
FSource:Pointer;
function GetValue: T;
procedure SetValue(const Value: T);
public
constructor Create(AOwner:TFMXObject;Source:Pointer;OnGetValue:TGetValueProc<T>;OnSetValue:TSetValueProc<T>);
class function Bind(AOwner:TFMXObject;Source:Pointer;OnGetValue:TGetValueProc<T>;OnSetValue:TSetValueProc<T>):TAnimationHelper<T>;
property Source:Pointer read FSource;
published
property Value:T read GetValue write SetValue;
end;
implementation
{ TAnimationHelper<T> }
class function TAnimationHelper<T>.Bind(AOwner: TFMXObject; Source: Pointer;
OnGetValue: TGetValueProc<T>;
OnSetValue: TSetValueProc<T>): TAnimationHelper<T>;
var
I:Integer;
begin
for I:=AOwner.ComponentCount-1 downto 0 do
begin
if (AOwner.Components[I] is TAnimationHelper<T>) and (TAnimationHelper<T>(AOwner.Components[I]).Source=Source) then
Exit(TAnimationHelper<T>(AOwner.Components[I]));
end;
Result:=TAnimationHelper<T>.Create(AOwner,Source,OnGetValue,OnSetValue);
Result.SetRoot(AOwner.Root);
end;
constructor TAnimationHelper<T>.Create(AOwner:TFMXObject;Source: Pointer;
OnGetValue: TGetValueProc<T>; OnSetValue: TSetValueProc<T>);
begin
inherited Create(AOwner);
FSource:=Source;
FOnGetValue:=OnGetValue;
FOnSetValue:=OnSetValue;
end;
function TAnimationHelper<T>.GetValue: T;
begin
if Assigned(FOnGetValue) then
FOnGetValue(Self,Result)
else
Result:=Default(T);
end;
procedure TAnimationHelper<T>.SetValue(const Value: T);
begin
if Assigned(FOnSetValue) then
FOnSetValue(Self,Value);
end;
end.
使用参考方法:
procedure TfrmFunction.SpeedButton6Click(Sender: TObject);
begin
TAnimator.AnimateFloat(TAnimationHelper<Single>.Bind(HorzScrollBox1,nil,
procedure (Sender:TObject;var V:Single)
begin
V:=HorzScrollBox1.ViewportPosition.X;
end,
procedure (Sender:TObject;const V:Single)
begin
HorzScrollBox1.ViewportPosition:=PointF(V,HorzScrollBox1.ViewportPosition.Y);
end
),'Value',HorzScrollBox1.ViewportPosition.X+HorzScrollBox1.Width/2,0.5);
end;
THorzScrollBox 里原来 ViewportPosition 是没法设置动画的,现在通过它适配下就可以创建动画效果了。

