Skip to content

Commit e5ee522

Browse files
committed
anim tweaks
1 parent 015868c commit e5ee522

File tree

4 files changed

+346
-1
lines changed

4 files changed

+346
-1
lines changed

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Defaults.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<SolidColorBrush x:Key="MaterialDesignLightBackground" Color="#FFFAFAFA"/>
3838
<SolidColorBrush x:Key="MaterialDesignLightForeground" Color="#DD000000"/>
3939
<SolidColorBrush x:Key="MaterialDesignDarkBackground" Color="#FF37474f"/>
40-
<SolidColorBrush x:Key="MaterialDesignDarkForeground" Color="#DDFFFFFF"/>
40+
<SolidColorBrush x:Key="MaterialDesignDarkForeground" Color="#FFFAFAFA"/>
4141
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignRaisedButton}" />
4242
<Style TargetType="{x:Type Calendar}" BasedOn="{StaticResource MaterialDesignCalendarPortrait}" />
4343
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MaterialDesignCheckBox}" />
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Media;
4+
using System.Windows.Media.Animation;
5+
6+
namespace MaterialDesignThemes.Wpf.Transitions
7+
{
8+
public class CircleWipe : ITransitionWipe
9+
{
10+
public void Wipe(TransitionerSlide fromSlide, TransitionerSlide toSlide, Point origin, IZIndexController zIndexController)
11+
{
12+
if (fromSlide == null) throw new ArgumentNullException(nameof(fromSlide));
13+
if (toSlide == null) throw new ArgumentNullException(nameof(toSlide));
14+
if (zIndexController == null) throw new ArgumentNullException(nameof(zIndexController));
15+
16+
var horizontalProportion = Math.Max(1.0 - origin.X, 1.0 * origin.X);
17+
var verticalProportion = Math.Max(1.0 - origin.Y, 1.0 * origin.Y);
18+
var radius = Math.Sqrt(Math.Pow(toSlide.ActualWidth * horizontalProportion, 2) + Math.Pow(toSlide.ActualHeight * verticalProportion, 2));
19+
20+
var scaleTransform = new ScaleTransform(0, 0);
21+
var translateTransform = new TranslateTransform(toSlide.ActualWidth * origin.X, toSlide.ActualHeight * origin.Y);
22+
var transformGroup = new TransformGroup();
23+
transformGroup.Children.Add(scaleTransform);
24+
transformGroup.Children.Add(translateTransform);
25+
var ellipseGeomotry = new EllipseGeometry()
26+
{
27+
RadiusX = radius,
28+
RadiusY = radius,
29+
Transform = transformGroup
30+
};
31+
32+
toSlide.SetCurrentValue(UIElement.ClipProperty, ellipseGeomotry);
33+
zIndexController.Stack(toSlide, fromSlide);
34+
35+
var zeroKeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
36+
var midKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(150));
37+
var endKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
38+
39+
var opacityAnimation = new DoubleAnimationUsingKeyFrames();
40+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, zeroKeyTime));
41+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, midKeyTime));
42+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, endKeyTime));
43+
opacityAnimation.Completed += (sender, args) =>
44+
{
45+
fromSlide.BeginAnimation(UIElement.OpacityProperty, null);
46+
fromSlide.Opacity = 0;
47+
};
48+
fromSlide.BeginAnimation(UIElement.OpacityProperty, opacityAnimation);
49+
50+
var scaleAnimation = new DoubleAnimationUsingKeyFrames();
51+
scaleAnimation.Completed += (sender, args) =>
52+
{
53+
toSlide.SetCurrentValue(UIElement.ClipProperty, null);
54+
fromSlide.Opacity = 0;
55+
};
56+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, zeroKeyTime));
57+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, endKeyTime));
58+
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
59+
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
60+
}
61+
}
62+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Media;
4+
using System.Windows.Media.Animation;
5+
6+
namespace MaterialDesignThemes.Wpf.Transitions
7+
{
8+
public class SlideOutWipe : ITransitionWipe
9+
{
10+
private readonly SineEase _sineEase = new SineEase();
11+
12+
public void Wipe(TransitionerSlide fromSlide, TransitionerSlide toSlide, Point origin, IZIndexController zIndexController)
13+
{
14+
if (fromSlide == null) throw new ArgumentNullException(nameof(fromSlide));
15+
if (toSlide == null) throw new ArgumentNullException(nameof(toSlide));
16+
if (zIndexController == null) throw new ArgumentNullException(nameof(zIndexController));
17+
18+
var zeroKeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
19+
var midishKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(100));
20+
var endKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
21+
22+
//back out old slide setup
23+
var scaleTransform = new ScaleTransform(1, 1);
24+
fromSlide.RenderTransform = scaleTransform;
25+
var scaleAnimation = new DoubleAnimationUsingKeyFrames();
26+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, zeroKeyTime));
27+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(.8, endKeyTime));
28+
scaleAnimation.Completed += (sender, args) =>
29+
{
30+
fromSlide.RenderTransform = null;
31+
};
32+
var opacityAnimation = new DoubleAnimationUsingKeyFrames();
33+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, zeroKeyTime));
34+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, endKeyTime));
35+
opacityAnimation.Completed += (sender, args) =>
36+
{
37+
fromSlide.BeginAnimation(UIElement.OpacityProperty, null);
38+
fromSlide.Opacity = 0;
39+
};
40+
41+
//slide in new slide setup
42+
var translateTransform = new TranslateTransform(0, toSlide.ActualHeight);
43+
toSlide.RenderTransform = translateTransform;
44+
var slideAnimation = new DoubleAnimationUsingKeyFrames();
45+
slideAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(toSlide.ActualHeight, zeroKeyTime));
46+
slideAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(toSlide.ActualHeight, midishKeyTime) { EasingFunction = _sineEase});
47+
slideAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, endKeyTime) { EasingFunction = _sineEase });
48+
49+
//kick off!
50+
translateTransform.BeginAnimation(TranslateTransform.YProperty, slideAnimation);
51+
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
52+
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
53+
fromSlide.BeginAnimation(UIElement.OpacityProperty, opacityAnimation);
54+
55+
zIndexController.Stack(toSlide, fromSlide);
56+
}
57+
}
58+
}
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Windows;
5+
using System.Windows.Controls;
6+
using System.Windows.Controls.Primitives;
7+
using System.Windows.Input;
8+
9+
namespace MaterialDesignThemes.Wpf.Transitions
10+
{
11+
/// <summary>
12+
/// The transitioner provides an easy way to move between content with a default in-place circular transition.
13+
/// </summary>
14+
public class Transitioner : Selector, IZIndexController
15+
{
16+
private Point? _nextTransitionOrigin;
17+
18+
static Transitioner()
19+
{
20+
DefaultStyleKeyProperty.OverrideMetadata(typeof(Transitioner), new FrameworkPropertyMetadata(typeof(Transitioner)));
21+
}
22+
23+
/// <summary>
24+
/// Causes the the next slide to be displayed (affectively increments <see cref="SelectedIndex"/>).
25+
/// </summary>
26+
public static RoutedCommand MoveNextCommand = new RoutedCommand();
27+
28+
/// <summary>
29+
/// Causes the the previous slide to be displayed (affectively decrements <see cref="SelectedIndex"/>).
30+
/// </summary>
31+
public static RoutedCommand MovePreviousCommand = new RoutedCommand();
32+
33+
/// <summary>
34+
/// Moves to the first slide.
35+
/// </summary>
36+
public static RoutedCommand MoveFirstCommand = new RoutedCommand();
37+
38+
/// <summary>
39+
/// Moves to the last slide.
40+
/// </summary>
41+
public static RoutedCommand MoveLastCommand = new RoutedCommand();
42+
43+
public static readonly DependencyProperty AutoApplyTransitionOriginsProperty = DependencyProperty.Register(
44+
"AutoApplyTransitionOrigins", typeof (bool), typeof (Transitioner), new PropertyMetadata(default(bool)));
45+
46+
public bool AutoApplyTransitionOrigins
47+
{
48+
get { return (bool) GetValue(AutoApplyTransitionOriginsProperty); }
49+
set { SetValue(AutoApplyTransitionOriginsProperty, value); }
50+
}
51+
52+
public Transitioner()
53+
{
54+
CommandBindings.Add(new CommandBinding(MoveNextCommand, MoveNextHandler));
55+
CommandBindings.Add(new CommandBinding(MovePreviousCommand, MovePreviousHandler));
56+
CommandBindings.Add(new CommandBinding(MoveFirstCommand, MoveFirstHandler));
57+
CommandBindings.Add(new CommandBinding(MoveLastCommand, MoveLastHandler));
58+
AddHandler(TransitionerSlide.InTransitionFinished, new RoutedEventHandler(IsTransitionFinishedHandler));
59+
Loaded += (sender, args) =>
60+
{
61+
if (SelectedIndex != -1)
62+
ActivateFrame(SelectedIndex, -1);
63+
};
64+
}
65+
66+
protected override bool IsItemItsOwnContainerOverride(object item)
67+
{
68+
return item is TransitionerSlide;
69+
}
70+
71+
protected override DependencyObject GetContainerForItemOverride()
72+
{
73+
return new TransitionerSlide();
74+
}
75+
76+
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
77+
{
78+
if (AutoApplyTransitionOrigins)
79+
_nextTransitionOrigin = GetNavigationSourcePoint(e);
80+
base.OnPreviewMouseLeftButtonDown(e);
81+
}
82+
83+
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
84+
{
85+
var unselectedIndex = -1;
86+
if (e.RemovedItems.Count == 1)
87+
{
88+
unselectedIndex = Items.IndexOf(e.RemovedItems[0]);
89+
}
90+
var selectedIndex = 1;
91+
if (e.AddedItems.Count == 1)
92+
{
93+
selectedIndex = Items.IndexOf(e.AddedItems[0]);
94+
}
95+
96+
ActivateFrame(selectedIndex, unselectedIndex);
97+
98+
base.OnSelectionChanged(e);
99+
}
100+
101+
private void IsTransitionFinishedHandler(object sender, RoutedEventArgs routedEventArgs)
102+
{
103+
foreach (var slide in Items.OfType<object>().Select(GetSlide).Where(s => s.State == TransitionerSlideState.Previous))
104+
{
105+
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.None);
106+
}
107+
}
108+
109+
private void MoveNextHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
110+
{
111+
_nextTransitionOrigin = GetNavigationSourcePoint(executedRoutedEventArgs);
112+
SetCurrentValue(SelectedIndexProperty, Math.Min(Items.Count - 1, SelectedIndex + 1));
113+
}
114+
115+
private void MovePreviousHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
116+
{
117+
_nextTransitionOrigin = GetNavigationSourcePoint(executedRoutedEventArgs);
118+
SetCurrentValue(SelectedIndexProperty, Math.Max(0, SelectedIndex - 1));
119+
}
120+
121+
private void MoveFirstHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
122+
{
123+
_nextTransitionOrigin = GetNavigationSourcePoint(executedRoutedEventArgs);
124+
SetCurrentValue(SelectedIndexProperty, 0);
125+
}
126+
127+
private void MoveLastHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
128+
{
129+
_nextTransitionOrigin = GetNavigationSourcePoint(executedRoutedEventArgs);
130+
SetCurrentValue(SelectedIndexProperty, Items.Count - 1);
131+
}
132+
133+
private Point? GetNavigationSourcePoint(RoutedEventArgs executedRoutedEventArgs)
134+
{
135+
var sourceElement = executedRoutedEventArgs.OriginalSource as FrameworkElement;
136+
if (sourceElement == null || !IsAncestorOf(sourceElement) || !IsSafePositive(ActualWidth) ||
137+
!IsSafePositive(ActualHeight) || !IsSafePositive(sourceElement.ActualWidth) ||
138+
!IsSafePositive(sourceElement.ActualHeight)) return null;
139+
140+
var transitionOrigin = sourceElement.TranslatePoint(new Point(sourceElement.ActualWidth / 2, sourceElement.ActualHeight), this);
141+
transitionOrigin = new Point(transitionOrigin.X / ActualWidth, transitionOrigin.Y / ActualHeight);
142+
return transitionOrigin;
143+
}
144+
145+
private static bool IsSafePositive(double dubz)
146+
{
147+
return !double.IsNaN(dubz) && !double.IsInfinity(dubz) && dubz > 0.0;
148+
}
149+
150+
private TransitionerSlide GetSlide(object item)
151+
{
152+
if (IsItemItsOwnContainer(item))
153+
return (TransitionerSlide)item;
154+
155+
return (TransitionerSlide)ItemContainerGenerator.ContainerFromItem(item);
156+
}
157+
158+
private void ActivateFrame(int selectedIndex, int unselectedIndex)
159+
{
160+
if (!IsLoaded) return;
161+
162+
TransitionerSlide oldSlide = null, newSlide = null;
163+
for (var index = 0; index < Items.Count; index++)
164+
{
165+
var slide = GetSlide(Items[index]);
166+
if (index == selectedIndex)
167+
{
168+
newSlide = slide;
169+
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Current);
170+
}
171+
else if (index == unselectedIndex)
172+
{
173+
oldSlide = slide;
174+
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Previous);
175+
}
176+
else
177+
{
178+
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.None);
179+
}
180+
Panel.SetZIndex(slide, 0);
181+
}
182+
183+
if (newSlide != null)
184+
newSlide.Opacity = 1;
185+
186+
if (oldSlide != null && newSlide != null)
187+
{
188+
var wipe = selectedIndex > unselectedIndex ? oldSlide.ForwardWipe : oldSlide.BackwardWipe;
189+
if (wipe != null)
190+
wipe.Wipe(oldSlide, newSlide, _nextTransitionOrigin ?? new Point(.5, .5), this);
191+
else
192+
{
193+
DoStack(newSlide, oldSlide);
194+
oldSlide.Opacity = 0;
195+
}
196+
}
197+
else if (oldSlide != null || newSlide != null)
198+
{
199+
DoStack(oldSlide ?? newSlide);
200+
if (oldSlide != null)
201+
{
202+
oldSlide.Opacity = 0;
203+
}
204+
}
205+
206+
_nextTransitionOrigin = null;
207+
}
208+
209+
void IZIndexController.Stack(params TransitionerSlide[] highestToLowest)
210+
{
211+
DoStack(highestToLowest);
212+
}
213+
214+
private static void DoStack(params TransitionerSlide[] highestToLowest)
215+
{
216+
if (highestToLowest == null) return;
217+
218+
var pos = highestToLowest.Length;
219+
foreach (var slide in highestToLowest.Where(s => s != null))
220+
{
221+
Panel.SetZIndex(slide, pos--);
222+
}
223+
}
224+
}
225+
}

0 commit comments

Comments
 (0)