【问题标题】:Delphi FMX TAnimator. How to animate a TPointF德尔福 FMX TAnimator。如何为 TPointF 设置动画
【发布时间】:2016-05-09 22:43:56
【问题描述】:

我的表单上有一个 TScrollbox。放置在 Scrollbox 上的是一个 TLayout,它比设备视口更宽更高,因此水平和垂直滚动条会显示出来,并且用户可以手动移动布局。

我还有一个手势设置,以便用户可以长按滚动框并将布局返回原点 (0,0)。

procedure TfrmMain.ScrollBox1Gesture(Sender: TObject;
  const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
  if EventInfo.GestureID = System.UITypes.igiLongTap then
  begin
     ScrollBox1.ViewportPosition := PointF(0, 0);
     ScrollBox1.RealignContent;
  end;

现在这很好用,但它发生得相当快。我想也许我可以使用:

TAnimator.AnimateFloat(Scrollbox1, 'ScrollBox1.ViewportPosition.X', 0, 0.3);

使从当前位置回到 0 的移动更温和一些,但是当然,这永远不会起作用,因为您不能直接为 PointF.XPointF.Y 赋值(因此也不能动画师)。

那么怎么做呢? 谢谢

【问题讨论】:

  • 子类 TScrollBox 并使用 getter 和 setter 方法实现 ViewPortPositionX property。
  • 谢谢,但我只是尝试开始这样做,并意识到我对类助手以及继承和覆盖返回值的保护方法知之甚少。
  • 请参阅Delphi subclass visual component and use it 以获取灵感。
  • 我要看看不同的解决方案,谢谢。这似乎是解决一个看似简单的问题的漫长道路。
  • 即。子类化一个 TAnimation 并创建一个 TAnimateFloatF 可能会更好

标签: delphi firemonkey


【解决方案1】:

由于缺少内置的PointAnimation,这里是一个自写的。

type
  TPointAnimation = class(TCustomPropertyAnimation)
  private
    FStartFloat: TPointF;
    FStartFromCurrent: Boolean;
    FStopFloat: TPointF;
  protected
    procedure FirstFrame; override;
    procedure ProcessAnimation; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property AnimationType default TAnimationType.In;
    property AutoReverse default False;
    property Delay;
    property Duration nodefault;
    property Enabled default False;
    property Interpolation default TInterpolationType.Linear;
    property Inverse default False;
    property Loop default False;
    property OnFinish;
    property OnProcess;
    property PropertyName;
    property StartFromCurrent: Boolean read FStartFromCurrent write
        FStartFromCurrent default False;
    property StartValue: TPointF read FStartFloat write FStartFloat stored True;
    property StopValue: TPointF read FStopFloat write FStopFloat stored True;
    property Trigger;
    property TriggerInverse;
  end;

constructor TPointAnimation.Create(AOwner: TComponent);
begin
  inherited;
  Duration := 0.2;
  FStartFloat := PointF(0, 0);
  FStopFloat := PointF(0, 0);
end;

procedure TPointAnimation.FirstFrame;
var
  T: TRttiType;
  P: TRttiProperty;
begin
  if StartFromCurrent then
  begin
    T := SharedContext.GetType(FInstance.ClassInfo);
    if T <> nil then
    begin
      P := T.GetProperty(FPath);
      if (P <> nil) and (P.PropertyType.TypeKind = tkRecord) then
        StartValue := P.GetValue(FInstance).AsType<TPointF>;
    end;
  end;
end;

procedure TPointAnimation.ProcessAnimation;
var
  newPoint: TPointF;
  T: TRttiType;
  P: TRttiProperty;
begin
  if FInstance <> nil then
  begin
    T := SharedContext.GetType(FInstance.ClassInfo);
    if T <> nil then
    begin
      P := T.GetProperty(FPath);
      if (P <> nil) and (P.PropertyType.TypeKind = tkRecord) then begin
        newPoint := PointF(InterpolateSingle(FStartFloat.X, FStopFloat.X, NormalizedTime),
                           InterpolateSingle(FStartFloat.Y, FStopFloat.Y, NormalizedTime));
        P.SetValue(FInstance, TValue.From<TPointF>(newPoint));
      end;
    end;
  end;
end;

在表单私有部分中声明一个字段

ani: TPointAnimation;

在 FormCreate 期间创建实例

ani := TPointAnimation.Create(Self);
ani.PropertyName := 'ViewportPosition';
ani.StartFromCurrent := true;
ani.Duration := 0.3;
ScrollBox1.AddObject(ani);

并在需要时启动它

ani.Start;

【讨论】:

  • 好东西。我希望你喜欢这个挑战。当然,你为我节省了很多工作。所以谢谢。
猜你喜欢
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 2022-07-12
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多