- goldsaucer
- Posts: 13
- Joined:
Triggering animation whenever screen is shown
I figured out to make a very simple animation. A UI element "bouncing" into the screen.
So far so good. But right now I'm using Border.Loaded to trigger it. Which of course only happens once.
But I'd like this to be triggered everytime I go back to this screen (without having to reload it every time).
I looked through the available events and I couldn't quite find one.
Is there another way to trigger this programmatically perhaps?
Code: Select all
<Border x:Name="MyBorder">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="-100"
To="0"
Duration="0:0:1"
Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
>
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.8" EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Border.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Border.RenderTransform>
<!-- ... -->
</Border>
But I'd like this to be triggered everytime I go back to this screen (without having to reload it every time).
I looked through the available events and I couldn't quite find one.
Is there another way to trigger this programmatically perhaps?
-
sfernandez
Site Admin
- Posts: 2983
- Joined:
Re: Triggering animation whenever screen is shown
In this scenario, where you want to animate a property of an element, you can use a DataTrigger in a Style:
You can modify border's IsEnabled property to trigger the animation.
To trigger an animation from code you just need to store it as a resource so you can grab it later:
If you are using C# SDK or Unity, having a reference to the root UI element where the Storyboard resource and target Border are defined, you can do:
In C++ it will be pretty much the same:
Code: Select all
<Border x:Name="MyBorder">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled, ElementName=MyBorder}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="-100"
To="0"
Duration="0:0:1"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
>
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.8" EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Border.RenderTransform>
<!-- ... -->
</Border>
To trigger an animation from code you just need to store it as a resource so you can grab it later:
Code: Select all
<Grid.Resources>
<Storyboard x:Key="BounceAnim">
<DoubleAnimation
From="-100"
To="0"
Duration="0:0:1"
Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
>
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.8" EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
Code: Select all
Storyboard bounceAnim = (Storyboard)root.FindResource("BounceAnim");
Border myBorder = (Border)root.FindName("MyBorder");
bounceAnim.Begin(myBorder);
Code: Select all
Storyboard* bounceAnim = root->FindResource<Storyboard>("BounceAnim");
Border* myBorder = root->FindName<Border>("MyBorder");
bounceAnim->Begin(myBorder);
- goldsaucer
- Posts: 13
- Joined:
Re: Triggering animation whenever screen is shown
Ah I see. I wonder why I hadn't thought the DataTrigger myself before. But especially being able to trigger the animation by making it a resource and using that in the code is super helpful. Thanks a lot!
-
sfernandez
Site Admin
- Posts: 2983
- Joined:
Re: Triggering animation whenever screen is shown
You're welcome.
- goldsaucer
- Posts: 13
- Joined:
Re: Triggering animation whenever screen is shown
This works fine with hard coded values. Do you know how to make it work with dynamic values / bindings, though?
I tried to do the following but get the exception below:
P.S. I'm actually trying to start from minus the height, but I have yet to write a custom converter for that.
P.P.S. Nevermind, it seems you can't use bindings in storyboards. But there is a (somewhat complicated) work around. See https://stackoverflow.com/questions/218 ... 5#14164245.
P.P.P.S. Ok that doesn't work after all because there is no IMultiValueConverter in Noesis. The simple approach (which doesn't work for control templates) may still work, though: https://stackoverflow.com/questions/515 ... -animation
P4.S. The simple approach doesn't work either, unfortuantely. Still getting the can't freeze error.
I tried to do the following but get the exception below:
Code: Select all
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding SlideInUI}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="{Binding ActualHeight, ElementName=MyBorder}"
To="0"
Duration="0:0:1"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
>
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.8" EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
Code: Select all
NoesisException: Can't Freeze BeginStoryboard.Storyboard
Rethrow as NoesisException
Noesis.Error.Check () (at Assets/NoesisGUI/Plugins/API/Core/NoesisError.cs:17)
Noesis.Texture.Noesis_WrapTexture_ (System.IntPtr texture, System.Int32 width, System.Int32 height, System.Int32 numLevels) (at Assets/NoesisGUI/Plugins/NoesisTexture.cs:22)
Noesis.Texture.WrapTexture (System.Object texture, System.IntPtr nativePointer, System.Int32 width, System.Int32 height, System.Int32 numLevels) (at Assets/NoesisGUI/Plugins/NoesisTexture.cs:11)
Noesis.TextureSource..ctor (UnityEngine.Texture2D texture) (at Assets/NoesisGUI/Plugins/NoesisTextureSource.cs:12)
AskutronGUI.Views.BaseControl`1[TM].TextureSourceForAction (Goldsaucer.Askutron.Players.PlayerAction action) (at Assets/Views/BaseControl.cs:151)
AskutronGUI.Views.BaseControl`1[TM].InitButtonTextures () (at Assets/Views/BaseControl.cs:88)
AskutronGUI.Views.BaseControl`1[TM].OnInitialized (System.Object sender, Noesis.EventArgs args) (at Assets/Views/BaseControl.cs:69)
Noesis.FrameworkElement.RaiseInitialized (System.IntPtr cPtr, System.IntPtr sender, System.IntPtr e) (at Assets/NoesisGUI/Plugins/API/Proxies/FrameworkElement.cs:247)
Rethrow as NoesisException
Noesis.Error.Check () (at Assets/NoesisGUI/Plugins/API/Core/NoesisError.cs:17)
Noesis.View.Noesis_View_Create_ (System.Runtime.InteropServices.HandleRef content) (at Assets/NoesisGUI/Plugins/API/Core/NoesisView.cs:402)
Noesis.View..ctor (Noesis.FrameworkElement content) (at Assets/NoesisGUI/Plugins/API/Core/NoesisView.cs:386)
NoesisView.CreateView (Noesis.FrameworkElement content) (at Assets/NoesisGUI/Plugins/NoesisView.cs:1036)
NoesisView.LoadXaml (System.Boolean force) (at Assets/NoesisGUI/Plugins/NoesisView.cs:340)
NoesisView.OnEnable () (at Assets/NoesisGUI/Plugins/NoesisView.cs:398)
P.P.S. Nevermind, it seems you can't use bindings in storyboards. But there is a (somewhat complicated) work around. See https://stackoverflow.com/questions/218 ... 5#14164245.
P.P.P.S. Ok that doesn't work after all because there is no IMultiValueConverter in Noesis. The simple approach (which doesn't work for control templates) may still work, though: https://stackoverflow.com/questions/515 ... -animation
P4.S. The simple approach doesn't work either, unfortuantely. Still getting the can't freeze error.
- goldsaucer
- Posts: 13
- Joined:
Re: Triggering animation whenever screen is shown
I'm actually quite baffled that this seems to be such a complicated issue to have dynamic values for an animation both in WPF and noesis.
I mean in WPF it's still possible although using a hack. But in noesis it seems to be simply impossible (due to the lack of MultiBindings). :S
Am I doing something wrong? Does no one ever want to animate things based on their actual dynamic dimensions rather than some hard coded values?
Even if use hard coded values I still have to scale those to work on different display sizes. Or is there a noesis feature I'm missing where hard coded values for widths, heights etc. are scaled automatically so that it looks the same on any screen? Right now I'm actually using bindings for that doing the scaling myself...
I mean in WPF it's still possible although using a hack. But in noesis it seems to be simply impossible (due to the lack of MultiBindings). :S
Am I doing something wrong? Does no one ever want to animate things based on their actual dynamic dimensions rather than some hard coded values?
Even if use hard coded values I still have to scale those to work on different display sizes. Or is there a noesis feature I'm missing where hard coded values for widths, heights etc. are scaled automatically so that it looks the same on any screen? Right now I'm actually using bindings for that doing the scaling myself...
- goldsaucer
- Posts: 13
- Joined:
Re: Triggering animation whenever screen is shown
Ok I found a programmatic solution. When entering the screen I trigger the animation via code as shown by sfernandez above.
The trick is to set the render transform of the element to its current ActualHeight/Width before starting the animation and not setting a `from` in the animation, because then it will just start where ever we put it using the render transform.
The trick is to set the render transform of the element to its current ActualHeight/Width before starting the animation and not setting a `from` in the animation, because then it will just start where ever we put it using the render transform.
Code: Select all
public void AnimateBorder()
{
// control is my currently shown screen which is a UserControl
Border border = Control.FindName("MyBorder") as Border;
Storyboard anim = (Storyboard) Control.FindResource("MyAnimation");
TranslateTransform transform = new TranslateTransform(0, -2 * border.ActualHeight);
border.RenderTransform = transform;
anim.Begin(border);
}
-
sfernandez
Site Admin
- Posts: 2983
- Joined:
Re: Triggering animation whenever screen is shown
The error about "Can't Freeze BeginStoryboard.Storyboard" is a problem we already fixed for the next version.
Have you tried to bind the transform property in the xaml itself using a converter?
Provided that you define a converter class called MultiplierConverter that accepts a param to multiply the bound value, and that you don't set the From value in the animation, this scenario should work.
Could you try that and let us know if find anything wrong?
Have you tried to bind the transform property in the xaml itself using a converter?
Code: Select all
<Border x:Name="MyBorder" ...>
<Border.RenderTransform>
<TranslateTransform Y="{Binding ActualHeight, ElementName=MyBorder, Converter={StaticResource MultiplierConverter}, ConverterParameter=-2}"/>
</Border.RenderTransform>
...
</Border>
Could you try that and let us know if find anything wrong?
- goldsaucer
- Posts: 13
- Joined:
Re: Triggering animation whenever screen is shown
Thanks, binding the actual height to the render transform's Y directly in XAML does work too!
-
sfernandez
Site Admin
- Posts: 2983
- Joined:
Re: Triggering animation whenever screen is shown
Great, thanks for your collaboration.
Who is online
Users browsing this forum: Google [Bot] and 92 guests