TransitionSystem - Axvser/MinimalisticWPF GitHub Wiki

简介

基于 State ( 状态 ) 的过渡自动加载框架,旨在为WPF动画提供极简的C#实现

  • 过渡作用于属性而非依赖属性,更加灵活
  • 线程安全的属性更新,即便过渡在非UI线程启动
  • 帧计算模块可拆卸、自定义
  • 提供接口以允许任何自定义类参与过渡

Ⅰ 过渡参数

TransitionParams类 提供了表格中的内容以描述一个过渡

分类 成员/属性/事件 描述
静态实例 TransitionParams.Theme 主题过渡效果的默认参数
TransitionParams.Hover 悬停过渡效果的默认参数
TransitionParams.Empty 空过渡效果的默认参数
效果参数 FrameRate 帧率,控制过渡效果的平滑度
Duration 持续时间,控制过渡效果的总时长
Acceleration 加速度,控制过渡效果的速度变化
IsAutoReverse 是否自动反向播放过渡效果
LoopTime 循环次数,控制过渡效果的重复次数
Priority 优先级,控制过渡效果的调度优先级
IsAsync 是否异步执行过渡效果
生命周期事件 Awaked 过渡效果初始化时触发的事件
Start 过渡效果开始时触发的事件
Update 过渡效果每帧更新时触发的事件
LateUpdate 过渡效果每帧更新后触发的事件
Canceled 过渡效果被取消时触发的事件
Completed 过渡效果完成时触发的事件
计算属性 DeltaTime 每帧的时间间隔,根据帧率计算
FrameCount 总帧数,根据持续时间和帧率计算
默认值 DefaultFrameRate 默认帧率
DefaultPriority 默认优先级
方法 Clone() 实现ICloneable接口,调用DeepCopy()

Ⅱ 串行动画

提供原子过渡,一个元素仅运行一个最新激活的过渡

    1. 用 Fluent API 构建过渡
  var control = new Grid();
  control.Transition()
      .SetProperty(x=>x.Background,Brushes.Red)
      .SetParams((p) =>
      {
          p.Duration = 3;
          p.IsAutoReverse = true;
          p.LoopTime = 2;
      })
      .Start();
    1. 用 TransitionBoard 复用过渡
  var control = new Grid();

  var param = new TransitionParams()
  {
      Duration = 3,
      IsAutoReverse = true,
      LoopTime = 2,
  };
  var transition1 = Transition.Create<Grid>()
      .SetProperty(x => x.Background, Brushes.Red)
      .SetParams(param);
  var transition2 = Transition.Create<Grid>()
      .SetProperty(x => x.Width, 100)
      .SetParams(param);

  var transition = Transition.Create([transition1, transition2]);

  control.BeginTransition(transition);

  // Transition.Dispose(control);

Ⅲ 并行动画

提供非原子过渡,一个元素可以同时执行多个过渡,特别注意是使用 BeginTransitions 而不是 BeginTransition

  var control = new Grid();

  var param1 = new TransitionParams()
  {
      Duration = 3,
      IsAutoReverse = true,
  };
  var param2 = new TransitionParams()
  {
      Duration = 1,
      LoopTime = 15
  };
  var transition1 = Transition.Create<Grid>()
      .SetProperty(x => x.Background, Brushes.Red)
      .SetParams(param1);
  var transition2 = Transition.Create<Grid>()
      .SetProperty(x => x.Width, 100)
      .SetProperty(x => x.Height, 100)
      .SetParams(param2);

  var schedulers = control.BeginTransitions(transition1, transition2);

  // schedulers[0].Dispose();
  // schedulers[1].Dispose();

Ⅳ 自定义插值计算模块

构建过渡时,无论使用Fluent API还是TransitionBoard,均可替换指定属性的插值计算逻辑

        public void LoadTransition()
        {
            var control = new Grid();
            control.Transition()
                .SetProperty(x => x.Background, Brushes.Red)
                .SetParams(TransitionParams.Hover)
                .SetCalculator(nameof(Grid.Background), Interpolate) // 将 Background 的插值逻辑覆写为自定义的插值逻辑 Interpolate
                .Start();
        }

        public static List<object?> Interpolate(object? current, object? target, double steps)
        {
            List<object?> list = [];

            // 实现自定义的插值逻辑

            return list;
        }

Ⅴ 自定义可过渡类

非WPF常见属性也可参与过渡自动生成,且由于依据你自定义插值逻辑执行过渡,效果而言可以很灵活

using MinimalisticWPF.StructuralDesign.Animator;

namespace DynamicTest_MinWpf
{
    public class MyClass : IInterpolable
    {
        public List<object?> Interpolate(object? current, object? target, int steps)
        {
            // 要求你提供一个统一方法,计算从 current 到 target 的插值集合 , 总计 steps 个插值

            // 发挥你的想象力,不仅仅是线性插值,一切皆有可能
        }
    }
}

Ⅵ 过渡预编译

基于过渡参数是一个引用类型,这在某些场景下可能导致意外的效果变动,尽管这种情况我没有遇到过,但是原则上必须提供这样的功能

  var control1 = new Grid();
  var control2 = new Grid();

  var param = new TransitionParams()
  {
      Duration = 3,
      IsAutoReverse = true,
      LoopTime = 2,
  };
  var transition1 = Transition.Create<Grid>()
      .SetProperty(x => x.Background, Brushes.Red)
      .SetParams(param);
  var transition2 = Transition.Create<Grid>()
      .SetProperty(x => x.Width, 100)
      .SetParams(param);

  var transition = Transition.Create([transition1, transition2]);
  var compile = Transition.Compile([transition1, transition2], param, null);

  param.LoopTime = 10; // 假设在这里,过渡参数被意外地修改了

  control1.BeginTransition(transition); // 循环 10次,受到引用类型的影响
  control2.BeginTransition(compile); // 循环 2次,不受外部影响,不可修改
⚠️ **GitHub.com Fallback** ⚠️