Animation (global offset) on Grid.Row - c#

I got this UserControl which is a Grid with around 10 rows and 10 columns. Each cell contains 1 textblock or 1-6 images.
What I want to do is animate all elements on each row to slide in. However I can't find a way to animate the whole Grid.Row to do that.
I can't wrap all elements in a stackpanel/canvas either since that puts them into the same column...
Anyone has a solution to this?
Thanks

So I've come up with a working solution and it is working. Maybe not that elegant but it does what it is supposed to do and works very well on a Lumia 920 device.
void CreateLoadAnimationForRow(int row, int startTime)
{
foreach (var child in LayoutRoot.Children.Cast<FrameworkElement>().Where(x => Grid.GetRow(x) == row))
{
AddToStoryboard(child, startTime);
}
}
void AddToStoryboard(FrameworkElement element, int startTime)
{
element.RenderTransform = new CompositeTransform();
var doubleAnimation = new DoubleAnimation
{
From = -200,
To = 0,
Duration = new Duration(TimeSpan.FromSeconds(1)),
BeginTime = TimeSpan.FromMilliseconds(startTime)
};
var objectAnimationUsingKeyFrames = new ObjectAnimationUsingKeyFrames()
{
BeginTime = TimeSpan.FromMilliseconds(startTime + 10)
};
var discreteObjectKeyFrame = new DiscreteObjectKeyFrame()
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0)),
Value = Visibility.Visible
};
objectAnimationUsingKeyFrames.KeyFrames.Add(discreteObjectKeyFrame);
IEasingFunction easingFunction = new SineEase();
easingFunction.Ease(2);
doubleAnimation.EasingFunction = easingFunction;
Storyboard.SetTarget(objectAnimationUsingKeyFrames, element);
Storyboard.SetTargetProperty(objectAnimationUsingKeyFrames, new PropertyPath("Visibility"));
Storyboard.SetTarget(doubleAnimation, element);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateX)"));
storyboardSlideIn.Children.Add(doubleAnimation);
storyboardSlideIn.Children.Add(objectAnimationUsingKeyFrames);
}

Related

How to animate a textblock so it appears as though it is bouncing on a surface in XAML or C#?

Hello, if this question is not clear or needs any improving/additional information please tell me in the comments.
I'm creating an app and in the game the user of the app gets xp by playing and winning challenges. I am interested in creating a bouncing text animation, here is what I'm wanting:
I heard you can simulate this using BounceEase but I have not found enough information/resources in order to achieve this certain effect.
I hope the information I have given is satisifatory enough in order for you to try to find a solution to this, if not, please tell me.
You can use the BounceEasy function to animate the y translation. Check the following demo.
void BounceText(string text, int x, int y)
{
var tb = new TextBlock
{
Text = text,
RenderTransform = new TranslateTransform(x, y)
};
RootCanvas.Children.Add(tb);
//--x animation 1
var xAnim = new DoubleAnimation(x, x + 40, new Duration(TimeSpan.FromSeconds(.6)));
Storyboard.SetTarget(xAnim, tb);
Storyboard.SetTargetProperty(xAnim, new PropertyPath("RenderTransform.X"));
//--x animation 2
var xAnim2 = new DoubleAnimation(x + 40, x + 80, new Duration(TimeSpan.FromSeconds(.6)))
{
BeginTime = TimeSpan.FromSeconds(0.6)
};
Storyboard.SetTarget(xAnim2, tb);
Storyboard.SetTargetProperty(xAnim2, new PropertyPath("RenderTransform.X"));
//--y animation
var yAnim = new DoubleAnimation(y, y - 40, new Duration(TimeSpan.FromSeconds(.3)))
{
AutoReverse = true,
EasingFunction = new BounceEase { EasingMode = EasingMode.EaseIn, Bounces = 0 },
RepeatBehavior = new RepeatBehavior(2)
};
Storyboard.SetTarget(yAnim, tb);
Storyboard.SetTargetProperty(yAnim, new PropertyPath("RenderTransform.Y"));
var sb = new Storyboard();
sb.Children.Add(xAnim);
sb.Children.Add(yAnim);
sb.Children.Add(xAnim2); //--add this to animate 2 times
sb.Begin();
}
Then you can use it like:
BounceText("+2 XP", 80, 80);
You can show the items using a canvas, for example:
...
<Canvas x:Name="RootCanvas"/>
...

TextBlock animation for Opacity not working as expected

I have a UWP app project and I am trying to add a couple of DoubleAnimations and I am using below code:
private static void CreateStoryboardAnimation(StackPanel sp, ItemHelper item, EnumHelper.AddRemoveFavorites favType)
{
var image = (Image)sp.FindName("ImageView");
var tb = (TextBlock)sp.FindName("FavStatusTB");
if (image != null)
{
image.RenderTransform = new CompositeTransform();
//tb.RenderTransform = new CompositeTransform();
Storyboard tbStory = new Storyboard();
var tbAnimateOpacity = new DoubleAnimation()
{
From = 1.0,
To = 0.0,
Duration = new Duration(TimeSpan.FromMilliseconds(500)),
};
Storyboard.SetTarget(tbAnimateOpacity, tb);
Storyboard.SetTargetProperty(tbAnimateOpacity, "Opacity");
tbStory.Children.Add(tbAnimateOpacity);
Storyboard storyboard1 = new Storyboard();
storyboard1.Completed += async delegate
{
// set text
if (favType == EnumHelper.AddRemoveFavorites.Add)
{
tb.Text = "Added to favorites";
}
else
{
tb.Text = "Removed from favorites";
}
await Task.Delay(500);
// run 2nd animation
var storyboard2 = new Storyboard();
var translateYAnimation2 = new DoubleAnimation()
{
From = -20,
To = 0,
Duration = new Duration(TimeSpan.FromMilliseconds(700)),
};
Storyboard.SetTarget(translateYAnimation2, image);
Storyboard.SetTargetProperty(translateYAnimation2, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
storyboard2.Children.Add(translateYAnimation2);
storyboard2.Begin();
tbStory.Begin();
};
DoubleAnimation translateYAnimation = new DoubleAnimation()
{
From = 0,
To = -20,
Duration = new Duration(TimeSpan.FromMilliseconds(500))
};
Storyboard.SetTarget(translateYAnimation, image);
Storyboard.SetTargetProperty(translateYAnimation, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
storyboard1.Children.Add(translateYAnimation);
storyboard1.Begin();
}
}
The first time I run the animation it works fine but after that it doesn't. This code gets applied on GridView items as you can see below:
The image animation works fine, it goes up and then the TextBlock animation runs poorly. It is supposed to display the text for 500 milliseconds but it shows the text and then starts the animation to make the opacity go zero.
I want this text to be visible to the user for at least 500 milliseconds and then the animation should start. Is there something that I am missing? I also tried BeginTime property of DoubleAnimation but to no avail. Please share your suggestions. Thanks
I think the problem is with the fact that you are starting the opacity animation inside the Completed handler of the first "slide up" animation. It works the first time, because the Opacity of the TextBlock is 1.0, but after the first round it is 0.0 and flips to 1.0 only after the await Task.Delay(500); finishes. The easiest fix would be to set the opacity right after the if:
if (image != null)
{
tb.Opacity = 1; //add this line
...

Making a user control pulse

What I'm trying to do is make my control "pulse" (as in enlarge a bit, then shrink a bit, then back to its normal size). The following code does exactly what I want, but it just seems like there should be a simpler way. It has to be done in code behind because this is an abstract class that most of our controls derive from. I don't have much experience with animation controls and story boards.
So specifically my question is, is there a simpler way to get the desired results than the following method (while still being done in the code-behind)?
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double changePercent = 20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
//enlarge
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
}
//shrink
{
DoubleAnimation shrinkX = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkX);
Storyboard.SetTargetProperty(shrinkX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation shrinkY = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkY);
Storyboard.SetTargetProperty(shrinkY, new PropertyPath("RenderTransform.ScaleY"));
}
//back to normal
{
DoubleAnimation normX = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normX);
Storyboard.SetTargetProperty(normX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation normY = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normY);
Storyboard.SetTargetProperty(normY, new PropertyPath("RenderTransform.ScaleY"));
}
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
You could perhaps simplify things a little by moving your grow/shrink logic into its own method. This reduces duplication and provides a potentially more reusable code kibble.
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double growPercent = 20;
double shrinkPercent = -20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
storyboard = AddSizeChange(firstTime, growPercent, storyboard);
storyboard = AddSizeChange(secondTime, shrinkPercent, storyboard);
storyboard = AddSizeChange(thirdTime, growPercent, storyboard);
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
public Storyboard AddSizeChange(TimeSpan animTime, double changePercent, Storyboard storyboard)
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
return storyboard;
}
That's a fine way of doing it, WPF does not provide methods or events to automatically pulse. Yours is simple and as you've created it, you know how to modify it as you wish.

Doubleanimation Skew not working

I am trying to get this animation to work but for some reason nothing is happening when it is called by the Dispatch timer, any ideas?
public static void Grass2(Canvas canvas, int boundry)
{
foreach (var element in canvas.Children.OfType<Image>())
{
var elementName = Regex.Split(element.Name, "_");
if (elementName[0] == "grass")
{
var skewGrass = new DoubleAnimation
{
From = 0,
To = boundry,
Duration = new Duration(TimeSpan.FromMilliseconds(100)),
RepeatBehavior = RepeatBehavior.Forever,
EasingFunction = new BackEase(),
AutoReverse = true
};
element.BeginAnimation(SkewTransform.AngleXProperty, skewGrass);
}
}
}
You're trying to animate the SkewTransform.AngleXProperty on an object of type Image. That won't work since Image does not have this property. However, the Image's RenderTransform might be set to a SkewTransform, and that SkewTransform can be animated:
...
// each element's RenderTransform must be a SkewTransform
var transform = (SkewTransform)element.RenderTransform;
transform.BeginAnimation(SkewTransform.AngleXProperty, skewGrass);

Convert C# animation code to storyboard

I have the following method which works. I'd like to put it in a utility method that returns a Storyboard. Every attempt I have made at converting this to a Storyboard has failed, and I've spent a lot of time researching. I'm ready to give up unless someone comes to my rescue.
Here's the code I want to convert:
public override void Begin(FrameworkElement element, int duration)
{
var transform = new ScaleTransform();
element.LayoutTransform = transform;
var animation = new DoubleAnimation
{
From = 1,
To = 0,
Duration = TimeSpan.FromMilliseconds(duration),
FillBehavior = FillBehavior.Stop,
EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseIn }
};
transform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
transform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}
So, instead of the two BeginAnimation() calls, I want to return a Storyboard so all I have to do is call storyboard.Begin(). I know this shouldn't be that hard to do, but I'm just not getting it.
Thanks.
EDIT: In response to H.B's suggestions, I tried the following code, which still does not work:
private static Storyboard CreateAnimationStoryboard(FrameworkElement element, int duration)
{
var sb = new Storyboard();
var scale = new ScaleTransform(1, 1);
element.RenderTransform = scale;
element.RegisterName("scale", scale);
var animation = new DoubleAnimation
{
From = 1,
To = 0,
Duration = TimeSpan.FromMilliseconds(duration),
FillBehavior = FillBehavior.Stop,
EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseIn }
};
sb.Children.Add(animation);
Storyboard.SetTarget(animation, scale);
Storyboard.SetTargetProperty(animation, new PropertyPath(ScaleTransform.ScaleXProperty));
return sb;
}
I know I only animated the X axis - just want to get something to work first.
You'll need two animations and then set the attached Storyboard properties to animated the right property on the right object using SetTargetProperty and SetTargetName.
Due to how storyboards work you also need to set a namescope (NameScope.SetNameScope), register the name of the transform, and call StoryBoard.Begin with the containing element overload.
e.g.
NameScope.SetNameScope(element, new NameScope());
var transform = new ScaleTransform();
var transformName = "transform";
element.RegisterName(transformName, transform);
element.RenderTransform = transform;
var xAnimation = new DoubleAnimation(2, TimeSpan.FromSeconds(1));
var yAnimation = xAnimation.Clone();
var storyboard = new Storyboard()
{
Children = { xAnimation, yAnimation }
};
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(ScaleTransform.ScaleX)"));
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(ScaleTransform.ScaleY)"));
Storyboard.SetTargetName(xAnimation, transformName);
Storyboard.SetTargetName(yAnimation, transformName);
storyboard.Begin(element);
I suggest using Expression Blend and start recording from there, it should create your storyboards in XAML. Rather than hard coding it with C# and trying to translate it 1 by 1 to storyboard thus it can be a prone error.

Categories

Resources