动画控件大小动态变化

时间:2016-07-11 11:38:03

标签: wpf animation

我目前正在开发某种具有“弹出”模式的菜单 - 意味着它仍然处于紧凑模式(仅约60px宽度),直到你鼠标悬停为止。主题是非常棘手的,因为你无法直接设置控件的宽度,并设置它会导致固定的大小(这不是我想要的)。

我的目标是让控件具有基于它的子项和最大值的动态大小。它的父母可用空间。

我的理论:一旦尺寸发生变化,就会调用测量来测量最大可用空间(远远超过将要使用的空间)。下一步是安排。使用参数 arrangeBounds 调用 ArrangeOverride(),该参数等于所需的大小。

现在我缓存此值,如果它与 ActualSize 属性不同,我会从 ActualSize arrangeBounds.Width 启动动画。该方法本身确实返回了像return base.ArrangeOverride(new Size(WidthWrapper, arrangeBounds.Height));

这样的Size对象

到目前为止,我已经有了这个(并且它部分正常工作 - WidthWrapper只是一个DependencyProperty):

protected override Size ArrangeOverride(Size arrangeBounds)
{
    if (Math.Abs(WidthWrapper) < 0.01)
        WidthWrapper = arrangeBounds.Width;

    if (Math.Abs(arrangeBounds.Width - ActualWidth) > 0.01)
    {
        if (_started & (Math.Abs(arrangeBounds.Width - _cache) < 0.01))
            return base.ArrangeOverride(new Size(WidthWrapper, arrangeBounds.Height));
        if (Math.Abs(arrangeBounds.Width - WidthWrapper) < 0.01)
            return base.ArrangeOverride(new Size(WidthWrapper, arrangeBounds.Height));

        if (_started & !_isExpanding)
        {
            Console.WriteLine("Re-Animate");
            // Change value
            if (_cache < arrangeBounds.Width)
                _isExpanding = true;
            _cache = arrangeBounds.Width;

            _board.Stop(this);
            _board.Children.Clear();
            _anim = new DoubleAnimation(WidthWrapper, arrangeBounds.Width,
                new Duration(TimeSpan.FromSeconds(0.8)))
            {
                EasingFunction = new QuadraticEase() {EasingMode = EasingMode.EaseInOut}
            };
            _board.Children.Add(_anim);
            Storyboard.SetTarget(_anim, this);
            Storyboard.SetTargetProperty(_anim, new PropertyPath(WidthWrapperProperty));
            _board.Begin(this);

            return base.ArrangeOverride(new Size(WidthWrapper, arrangeBounds.Height));
        }

        if (!_started)
        {
            if (_cache < arrangeBounds.Width)
                _isExpanding = true;
            _cache = arrangeBounds.Width;
            _anim = new DoubleAnimation(WidthWrapper, arrangeBounds.Width,
                new Duration(TimeSpan.FromSeconds(1.5)))
            {
                EasingFunction = new QuadraticEase() {EasingMode = EasingMode.EaseInOut}
            };
            _board.Children.Add(_anim);
            Storyboard.SetTarget(_anim, this);
            Storyboard.SetTargetProperty(_anim, new PropertyPath(WidthWrapperProperty));
            _board.Begin(this, true);
            _started = true;
        }
    }

    Size animatedSize = new Size(WidthWrapper, arrangeBounds.Height);
    return base.ArrangeOverride(animatedSize);
}

启动测试项目时,菜单以几乎全尺寸开始,你会看到它的一部分从右边“淡入” - 看起来非常酷。现在的问题是,当我切换到紧凑模式时,没有动画。它立即变成~61px宽。当我将鼠标悬停在它上面时,你会看到它在扩展但是闪烁并随机跳回到之前的大小。

问题显然是使用这种方法错误地控制了控件。在做这个动画时,它看起来有点偏离右侧。因此,不再检测到鼠标悬停,并且它试图动画回到紧凑的尺寸。这种情况经常发生,直到动画完成并最终达到完整大小(如果它完全达到)。

它的父母似乎是某种安置问题。我在这里加了一个GIF,所以你可以看到我的意思。

Animation

PS:我禁用了“flyout”模式,但是即使从普通模式切换到紧凑模式也有问题(虽然它部分有效但看起来很不错)。

任何想法如何解决这个问题,使其顺利扩展,没有任何闪烁和其他问题?专业UI库具有例如对接窗口,其在取消固定时快速淡出。我想以某种方式将这种效果应用到我的菜单中。我认为这是可能的,因为我已经接近了 - 但显然WPF不支持它没有一点诡计。

1 个答案:

答案 0 :(得分:2)

查看Visual State ManagerTranslate Transform

基本上你会想要描述一个开放和闭合状态,并使用变换来动画状态之间的运动。