本增强的目的是解决动画对象只支持 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 是没法设置动画的,现在通过它适配下就可以创建动画效果了。