【问题标题】:UI element's animation?UI元素的动画?
【发布时间】:2015-03-15 19:33:16
【问题描述】:

我是 Windows Phone 开发的新手,所以我对 Storyboards 不是很熟悉,不知道他们是否适合我这种情况。

我有一个Canvas,我在上面放置了一个Rectangle。当我调用它的 move 方法时,我希望 Rectangle 在随机方向上平滑移动(通过处理平移和选择 x 和 y 来处理)。

我在游戏 Breakout 之前制作了一个简单的 Java 应用程序,我通过在 while 循环中将球移动到非常靠近的位置并暂停 while 循环一定量来处理球的运动,以便您可以看到球的动画窗内的动静。我想知道在这种情况下是否可以使用 while 循环来做同样的事情,因为我相信这将是我计划用我的应用程序做的最好的事情。

点击矩形时我尝试了以下操作:

private void TestRectangle_Tapped(object sender, TappedRoutedEventArgs e)
{
    int x = 1;
    while (x < 50)
    {
         double d = Canvas.GetLeft(TestRectangle);
         Canvas.SetLeft(TestRectangle, d + 1);
         TestCanvas.UpdateLayout();
         System.Threading.Tasks.Task.Delay(5).Wait();
         x++;
    }
   /*
    int y = 1;
    while(y < 200)
    {
        dragTranslation.Y += 1;
        TestCanvas.UpdateLayout();
        System.Threading.Tasks.Task.Delay(1).Wait();
        y++;
    }
    * */  
}

问题是它的更新速度不够快,所以当矩形移动时我没有得到平滑的动画,点击时它几乎跳到了它的最终位置。

我如何才能做到这一点,因为我最终希望使 Rectangle 在屏幕周围随机移动并与 Canvas 的边缘发生碰撞?

如果我不得不求助于Storyboard,有人可以指出一个沿随机路径移动对象的示例(使用 C# 而不是 XAML)。

【问题讨论】:

    标签: c# xaml animation windows-phone-8.1


    【解决方案1】:

    XAML 和 Expression Blend 是创建动画的简单方法。

    这是定义情节提要和动画的 XAML。

    XAML

    <Page.Resources>
      <Storyboard x:Name="MoveRectangleStoryboard"
                  Completed='MoveRectangle_Completed'>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
                                        Storyboard.TargetName="TestRectangle">
          <EasingDoubleKeyFrame KeyTime="0"
                                Value="0"
                                x:Name='xKey1' />
          <EasingDoubleKeyFrame KeyTime="0:0:2"
                                Value="165.423"
                                x:Name='xKey2' />
    
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
                                        Storyboard.TargetName="TestRectangle">
          <EasingDoubleKeyFrame KeyTime="0"
                                Value="0"
                                x:Name='yKey1' />
          <EasingDoubleKeyFrame KeyTime="0:0:2"
                                Value="68.408"
                                x:Name='yKey2' />
    
        </DoubleAnimationUsingKeyFrames>
      </Storyboard>
    </Page.Resources>
    
      <Canvas x:Name='MainCanvas'>
        <Rectangle x:Name="TestRectangle"
                   Fill='Orange'
                   Tapped='rectangle_Tapped'
                   Width='60'
                   Height='80'
                   RenderTransformOrigin="0.0,0.0">
          <Rectangle.RenderTransform>
            <CompositeTransform />
          </Rectangle.RenderTransform>
        </Rectangle>
      </Canvas>
    

    代码

    Random ran = new Random();
    private void MoveRectangle_Completed(object sender, object e) {
      xKey1.Value = xKey2.Value;
      xKey2.Value = ran.NextDouble() * (MainCanvas.ActualWidth - TestRectangle.ActualWidth);
      yKey1.Value = yKey2.Value;
      yKey2.Value = ran.NextDouble() * (MainCanvas.ActualHeight - TestRectangle.ActualHeight);
    
    }
    
    private void rectangle_Tapped(object sender, TappedRoutedEventArgs e) {
      MoveRectangleStoryboard.Begin();
    }
    

    【讨论】:

    • 我知道您只要求 C#,但我发现使用 Blend 生成动画很容易,然后在文本编辑器和代码编辑器中编辑结果。
    【解决方案2】:

    代码中 UIElement 的 Canvas.LeftCanvas.Top 属性的简单动画如下所示:

    public void MoveElement(
        UIElement element, double offsetX, double offsetY, TimeSpan duration)
    {
        var xAnimation = new DoubleAnimation
        {
            To = Canvas.GetLeft(element) + offsetX,
            Duration = duration,
        };
    
        var yAnimation = new DoubleAnimation
        {
            To = Canvas.GetTop(element) + offsetY,
            Duration = duration,
        };
    
        Storyboard.SetTarget(xAnimation, element);
        Storyboard.SetTargetProperty(xAnimation, "(Canvas.Left)");
        Storyboard.SetTarget(yAnimation, element);
        Storyboard.SetTargetProperty(yAnimation, "(Canvas.Top)");
    
        var storyboard = new Storyboard();
        storyboard.Children.Add(xAnimation);
        storyboard.Children.Add(yAnimation);
        storyboard.Begin();
    }
    

    您可以像这样在您的 Tapped 处理程序中使用它:

    private void TestRectangle_Tapped(object sender, TappedRoutedEventArgs e)
    {
        MoveElement(TestRectangle, 50, 50, TimeSpan.FromSeconds(0.25));
    }
    

    或者不命名矩形,像这样:

    private void TestRectangle_Tapped(object sender, TappedRoutedEventArgs e)
    {
        MoveElement((UIElement)sender, 50, 50, TimeSpan.FromSeconds(0.25));
    }
    

    【讨论】:

    • 好的,谢谢。我有一些问题。当我尝试此操作时,我收到一条错误消息,提示找不到类型或命名空间名称 DoubleAnimation 并且 System.Windows.Media.Animation.Storyboard 不包含“儿童”的定义。我错过了什么?谢谢。
    • 没关系。我想我想通了。缺少对 Windows.UI.Xaml.Media.Animation 的引用;
    • 如何添加它以使其无限期运行?我最终希望它继续移动直到满足条件并让它检查它是否弹回画布的边界等(我假设我会检查它是否超出了 (To = Canvas.GetLeft(element ) + 偏移量?)?我尝试了,但它进入了一个 while 循环,但我的应用程序无法打开。
    • 当我只想让它继续向它的方向移动(如果它撞到墙上,改变 x 或 y)直到满足条件时,重复行为也会重置动画?将持续时间设置为较长时间是否更好,因为我还计划如果在一定时间后不满足条件,我希望“游戏结束”。
    • 如果您希望动画一直运行到对象“撞墙”,则在开始动画之前计算相对于当前位置的移动距离(和持续时间)。为了在动画完成时收到通知,Storyboard 有一个 Completed 事件。附加一个事件处理程序并在那里开始另一个动作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多