欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF中自定义GridLengthAnimation

程序员文章站 2023-11-17 09:09:40
需求 我们想在编辑一个列表中某一个条目时,将编辑的详情内容也放置当前面,比如右侧。 可以通过将一个grid,分成两个cloumn,动态调整两个cloumn的widt...

需求

我们想在编辑一个列表中某一个条目时,将编辑的详情内容也放置当前面,比如右侧。

可以通过将一个grid,分成两个cloumn,动态调整两个cloumn的width,就可以实现这个需求。

我们知道,clomun的width是个,而默认的动画没有这样子的。我们就需要自己实现这样一人动画。

设计
我们从animation的类图上看到

WPF中自定义GridLengthAnimation

我们可以从需求

我们想在编辑一个列表中某一个条目时,将编辑的详情内容也放置当前面,比如右侧。

可以通过将一个grid,分成两个cloumn,动态调整两个cloumn的width,就可以实现这个需求。

我们知道,clomun的width是个gridlength,而默认的动画没有这样子的。我们就需要自己实现这样一人动画。

设计

我们从animation的类图上看到animationtimeline继承,重写其getcurrentvalue

public class gridlengthanimation : animationtimeline
  {
    /// <summary>
    /// returns the type of object to animate
    /// </summary>
    public override type targetpropertytype => typeof(gridlength);
 
    /// <summary>
    /// creates an instance of the animation object
    /// </summary>
    /// <returns>returns the instance of the gridlengthanimation</returns>
    protected override system.windows.freezable createinstancecore()
    {
      return new gridlengthanimation();
    }
 
    /// <summary>
    /// dependency property for the from property
    /// </summary>
    public static readonly dependencyproperty fromproperty = dependencyproperty.register("from", typeof(gridlength),
      typeof(gridlengthanimation));
 
    /// <summary>
    /// clr wrapper for the from depenendency property
    /// </summary>
    public gridlength from
    {
      get
      {
        return (gridlength)getvalue(gridlengthanimation.fromproperty);
      }
      set
      {
        setvalue(gridlengthanimation.fromproperty, value);
      }
    }
 
    /// <summary>
    /// dependency property for the to property
    /// </summary>
    public static readonly dependencyproperty toproperty = dependencyproperty.register("to", typeof(gridlength),
      typeof(gridlengthanimation));
 
    /// <summary>
    /// clr wrapper for the to property
    /// </summary>
    public gridlength to
    {
      get
      {
        return (gridlength)getvalue(gridlengthanimation.toproperty);
      }
      set
      {
        setvalue(gridlengthanimation.toproperty, value);
      }
    }
 
    /// <summary>
    /// animates the grid let set
    /// </summary>
    /// <param name="defaultoriginvalue">the original value to animate</param>
    /// <param name="defaultdestinationvalue">the final value</param>
    /// <param name="animationclock">the animation clock (timer)</param>
    /// <returns>returns the new grid length to set</returns>
    public override object getcurrentvalue(object defaultoriginvalue,
      object defaultdestinationvalue, animationclock animationclock)
    {
      double fromval = ((gridlength)getvalue(gridlengthanimation.fromproperty)).value;
 
      double toval = ((gridlength)getvalue(gridlengthanimation.toproperty)).value;
 
      if (fromval > toval)
        return new gridlength((1 - animationclock.currentprogress.value) * (fromval - toval) + toval, gridunittype.star);
      else
        return new gridlength(animationclock.currentprogress.value * (toval - fromval) + fromval, gridunittype.star);
    }

如上所示,我们仿着默认动画实现了from,to,同时将其属性定义为gridlength,当动画执行时,我们重写了getcurrentvalue,使其根据from/to属性相关联。

优化

通过以上代码,我们实现了在gridlength变化时,实现动画。但是,试用后我们发现,动画,有点太线性。这个时候,怎么办?

可以通过引入easingfunction来实现。我们知道easingfunction其实就是一个与时间t有关的时间函数f(t).通过时间函数的处理,我们使动画过渡不要那么线性。

 /// <summary>
    /// the <see cref="easingfunction" /> dependency property's name.
    /// </summary>
    public const string easingfunctionpropertyname = "easingfunction";
 
    /// <summary>
    /// gets or sets the value of the <see cref="easingfunction" />
    /// property. this is a dependency property.
    /// </summary>
    public ieasingfunction easingfunction
    {
      get
      {
        return (ieasingfunction)getvalue(easingfunctionproperty);
      }
      set
      {
        setvalue(easingfunctionproperty, value);
      }
    }
 
    /// <summary>
    /// identifies the <see cref="easingfunction" /> dependency property.
    /// </summary>
    public static readonly dependencyproperty easingfunctionproperty = dependencyproperty.register(
      easingfunctionpropertyname,
      typeof(ieasingfunction),
      typeof(gridlengthanimation),
      new uipropertymetadata(null));

对应的,还要重写getcurrentvalue函数。

public override object getcurrentvalue(object defaultoriginvalue,
      object defaultdestinationvalue, animationclock animationclock)
    {
      double fromval = ((gridlength)getvalue(fromproperty)).value;
 
      double toval = ((gridlength)getvalue(toproperty)).value;
 
      //check that from was set from the caller
      //if (fromval == 1)
      //  //set the from as the actual value
      //  fromval = ((gridlength)defaultdestinationvalue).value;
 
      double progress = animationclock.currentprogress.value;
 
      ieasingfunction easingfunction = easingfunction;
      if (easingfunction != null)
      {
        progress = easingfunction.ease(progress);
      }
 
 
      if (fromval > toval)
        return new gridlength((1 - progress) * (fromval - toval) + toval, gridunittype.star);
 
        return new gridlength(progress * (toval - fromval) + fromval, gridunittype.star);
    }

使用

 <anim:gridlengthanimation storyboard.targetproperty="width" from="0" to="*" duration="0:0:0.5"/>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。