[FMX] FMX 动画类的一个辅助增强

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

分享到: