Skip to content

Commit 670fe5e

Browse files
committed
wipes in effect
1 parent 74424ce commit 670fe5e

File tree

9 files changed

+168
-69
lines changed

9 files changed

+168
-69
lines changed

MainDemo.Wpf/TransitionsDemo/TransitionsDemoHome.xaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@
2525
<!-- but you can use bare xaml too -->
2626
<local:Slide2_Intro />
2727

28-
<local:Slide3_Intro />
28+
<!-- you can control (and create your own) wipes -->
29+
<materialDesign:TransitionerSlide>
30+
<materialDesign:TransitionerSlide.BackwardWipe>
31+
<materialDesign:CircleWipe />
32+
</materialDesign:TransitionerSlide.BackwardWipe>
33+
<local:Slide3_Intro />
34+
</materialDesign:TransitionerSlide>
2935

3036
<!-- now we are going to slide this in by combining some extra effects. the inner content slides in, so we'll set the outer background and clip, to keep things nice -->
3137
<materialDesign:TransitionerSlide Background="{DynamicResource MaterialDesignDarkBackground}"

MaterialDesignThemes.Wpf/MaterialDesignThemes.Wpf.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@
255255
<Compile Include="Extensions.cs" />
256256
<Compile Include="Icon.cs" />
257257
<Compile Include="IconType.cs" />
258+
<Compile Include="Transitions\CircleWipe.cs" />
258259
<Compile Include="Transitions\ITransitionEffect.cs" />
259260
<Compile Include="Transitions\ITransitionEffectSubject.cs" />
260261
<Compile Include="Transitions\ITransitionWipe.cs" />
@@ -291,6 +292,7 @@
291292
<Compile Include="ToolTipAssist.cs" />
292293
<Compile Include="RippleAssist.cs" />
293294
<Compile Include="Ripple.cs" />
295+
<Compile Include="Transitions\IZIndexController.cs" />
294296
<Compile Include="Transitions\TransitionAssist.cs" />
295297
<Compile Include="Transitions\TransitionEffect.cs" />
296298
<Compile Include="Transitions\TransitionEffectBase.cs" />

MaterialDesignThemes.Wpf/Themes/Generic.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@
809809
</Style>
810810

811811
<Style TargetType="{x:Type transitions:Transitioner}">
812+
<Setter Property="ClipToBounds" Value="True" />
812813
<Setter Property="ItemsPanel">
813814
<Setter.Value>
814815
<ItemsPanelTemplate>
@@ -868,6 +869,7 @@
868869
<Style TargetType="{x:Type transitions:TransitioningContent}" BasedOn="{StaticResource {x:Type transitions:TransitioningContentBase}}" />
869870

870871
<Style TargetType="{x:Type transitions:TransitionerSlide}" BasedOn="{StaticResource {x:Type transitions:TransitioningContentBase}}">
872+
<Setter Property="RenderTransformOrigin" Value=".5,.5" />
871873
<Setter Property="IsEnabled" Value="False" />
872874
<Setter Property="Visibility" Value="Hidden" />
873875
<Style.Triggers>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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 endKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
37+
38+
var scaleAnimation = new DoubleAnimationUsingKeyFrames();
39+
scaleAnimation.Completed += (sender, args) =>
40+
{
41+
toSlide.SetCurrentValue(UIElement.ClipProperty, null);
42+
};
43+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, zeroKeyTime));
44+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, endKeyTime));
45+
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
46+
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
47+
}
48+
}
49+
50+
public class SlideOutWipe : ITransitionWipe
51+
{
52+
private readonly SineEase _sineEase = new SineEase();
53+
54+
public void Wipe(TransitionerSlide fromSlide, TransitionerSlide toSlide, Point origin, IZIndexController zIndexController)
55+
{
56+
if (fromSlide == null) throw new ArgumentNullException(nameof(fromSlide));
57+
if (toSlide == null) throw new ArgumentNullException(nameof(toSlide));
58+
if (zIndexController == null) throw new ArgumentNullException(nameof(zIndexController));
59+
60+
var zeroKeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
61+
var endKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
62+
63+
//back out old slide setup
64+
var scaleTransform = new ScaleTransform(1, 1);
65+
fromSlide.RenderTransform = scaleTransform;
66+
var scaleAnimation = new DoubleAnimationUsingKeyFrames();
67+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, zeroKeyTime));
68+
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(.8, endKeyTime));
69+
scaleAnimation.Completed += (sender, args) =>
70+
{
71+
fromSlide.RenderTransform = null;
72+
};
73+
74+
//slide in new slide setup
75+
var translateTransform = new TranslateTransform(0, toSlide.ActualHeight);
76+
toSlide.RenderTransform = translateTransform;
77+
var slideAnimation = new DoubleAnimationUsingKeyFrames();
78+
slideAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(toSlide.ActualHeight, zeroKeyTime) { EasingFunction = _sineEase});
79+
slideAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, endKeyTime) { EasingFunction = _sineEase });
80+
81+
//kick off!
82+
translateTransform.BeginAnimation(TranslateTransform.YProperty, slideAnimation);
83+
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
84+
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
85+
86+
zIndexController.Stack(toSlide, fromSlide);
87+
}
88+
}
89+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
using System.Windows;
2+
13
namespace MaterialDesignThemes.Wpf.Transitions
24
{
35
public interface ITransitionWipe
46
{
5-
bool IsDestinationTopmostForDuration { get; }
6-
7-
void Wipe(TransitionerSlide from, TransitionerSlide to);
7+
void Wipe(TransitionerSlide fromSlide, TransitionerSlide toSlide, Point origin, IZIndexController zIndexController);
88
}
99
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace MaterialDesignThemes.Wpf.Transitions
2+
{
3+
public interface IZIndexController
4+
{
5+
void Stack(params TransitionerSlide[] highestToLowest);
6+
}
7+
}

MaterialDesignThemes.Wpf/Transitions/TransitionEffect.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public override Timeline Build<TSubject>(TSubject effectSubject)
5959
targetName = effectSubject.TranslateTransformName;
6060
break;
6161
case TransitionEffectKind.SlideInFromBottom:
62-
timeline = new DoubleAnimation { EasingFunction = new SineEase(), From = 300, To = 0 };
62+
timeline = new DoubleAnimation { EasingFunction = new SineEase(), From = 300, To = 0, };
6363
property = TranslateTransform.YProperty;
6464
targetName = effectSubject.TranslateTransformName;
6565
break;

MaterialDesignThemes.Wpf/Transitions/Transitioner.cs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Windows;
45
using System.Windows.Controls;
@@ -10,7 +11,7 @@ namespace MaterialDesignThemes.Wpf.Transitions
1011
/// <summary>
1112
/// The transitioner provides an easy way to move between content with a default in-place circular transition.
1213
/// </summary>
13-
public class Transitioner : Selector
14+
public class Transitioner : Selector, IZIndexController
1415
{
1516
private Point? _nextTransitionOrigin;
1617

@@ -140,31 +141,62 @@ private TransitionerSlide GetSlide(object item)
140141

141142
private void ActivateFrame(int selectedIndex, int unselectedIndex)
142143
{
143-
if (!IsLoaded) return;
144+
if (!IsLoaded) return;
144145

146+
TransitionerSlide oldSlide = null, newSlide = null;
145147
for (var index = 0; index < Items.Count; index++)
146148
{
147149
var slide = GetSlide(Items[index]);
148150
if (index == selectedIndex)
149151
{
150-
Panel.SetZIndex(slide, 2);
151-
if (_nextTransitionOrigin != null)
152-
slide.OverrideOnce(_nextTransitionOrigin.Value);
153-
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Current);
152+
newSlide = slide;
153+
// slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Current);
154154
}
155155
else if (index == unselectedIndex)
156156
{
157-
Panel.SetZIndex(slide, 1);
158-
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Previous);
157+
oldSlide = slide;
158+
//slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Previous);
159159
}
160160
else
161-
{
162-
Panel.SetZIndex(slide, 0);
161+
{
163162
slide.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.None);
164163
}
164+
Panel.SetZIndex(slide, 0);
165+
}
166+
167+
if (oldSlide != null && newSlide != null)
168+
{
169+
var wipe = selectedIndex > unselectedIndex ? oldSlide.ForwardWipe : oldSlide.BackwardWipe;
170+
if (wipe != null)
171+
wipe.Wipe(oldSlide, newSlide, _nextTransitionOrigin ?? new Point(.5, .5), this);
172+
else
173+
DoStack(newSlide, oldSlide);
165174
}
175+
else if (oldSlide != null || newSlide != null)
176+
{
177+
DoStack(oldSlide ?? newSlide);
178+
}
179+
180+
newSlide?.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Current);
181+
oldSlide?.SetCurrentValue(TransitionerSlide.StateProperty, TransitionerSlideState.Previous);
166182

167183
_nextTransitionOrigin = null;
168-
}
184+
}
185+
186+
void IZIndexController.Stack(params TransitionerSlide[] highestToLowest)
187+
{
188+
DoStack(highestToLowest);
189+
}
190+
191+
private static void DoStack(params TransitionerSlide[] highestToLowest)
192+
{
193+
if (highestToLowest == null) return;
194+
195+
var pos = highestToLowest.Length;
196+
foreach (var slide in highestToLowest.Where(s => s != null))
197+
{
198+
Panel.SetZIndex(slide, pos--);
199+
}
200+
}
169201
}
170202
}

MaterialDesignThemes.Wpf/Transitions/TransitionerSlide.cs

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ namespace MaterialDesignThemes.Wpf.Transitions
1313
/// </summary>
1414
public class TransitionerSlide : TransitioningContentBase
1515
{
16-
private Point? _overrideTransitionOrigin;
17-
1816
static TransitionerSlide()
1917
{
2018
DefaultStyleKeyProperty.OverrideMetadata(typeof(TransitionerSlide), new FrameworkPropertyMetadata(typeof(TransitionerSlide)));
@@ -40,68 +38,31 @@ public TransitionerSlideState State
4038
{
4139
get { return (TransitionerSlideState) GetValue(StateProperty); }
4240
set { SetValue(StateProperty, value); }
43-
}
41+
}
4442

45-
//TODO validate inputs
46-
public static readonly DependencyProperty TransitionOriginProperty = DependencyProperty.Register("TransitionOrigin", typeof (Point), typeof (TransitionerSlide), new PropertyMetadata(new Point(.5, .5)));
43+
public static readonly DependencyProperty ForwardWipeProperty = DependencyProperty.Register(
44+
"ForwardWipe", typeof (ITransitionWipe), typeof (TransitionerSlide), new PropertyMetadata(new CircleWipe()));
4745

48-
public Point TransitionOrigin
46+
public ITransitionWipe ForwardWipe
4947
{
50-
get { return (Point) GetValue(TransitionOriginProperty); }
51-
set { SetValue(TransitionOriginProperty, value); }
48+
get { return (ITransitionWipe) GetValue(ForwardWipeProperty); }
49+
set { SetValue(ForwardWipeProperty, value); }
5250
}
5351

54-
internal void OverrideOnce(Point transitionOrigin)
52+
public static readonly DependencyProperty BackwardWipeProperty = DependencyProperty.Register(
53+
"BackwardWipe", typeof (ITransitionWipe), typeof (TransitionerSlide), new PropertyMetadata(new SlideOutWipe()));
54+
55+
public ITransitionWipe BackwardWipe
5556
{
56-
_overrideTransitionOrigin = transitionOrigin;
57+
get { return (ITransitionWipe) GetValue(BackwardWipeProperty); }
58+
set { SetValue(BackwardWipeProperty, value); }
5759
}
5860

5961
private void AnimateToState()
6062
{
61-
if (State != TransitionerSlideState.Current) return;
62-
63-
RunInTransitionIn();
63+
if (State != TransitionerSlideState.Current) return;
6464

6565
RunOpeningEffects();
66-
}
67-
68-
protected virtual void RunInTransitionIn()
69-
{
70-
var transitionOrigin = _overrideTransitionOrigin ?? TransitionOrigin;
71-
_overrideTransitionOrigin = null;
72-
73-
var horizontalProportion = Math.Max(1.0 - transitionOrigin.X, 1.0*transitionOrigin.X);
74-
var verticalProportion = Math.Max(1.0 - transitionOrigin.Y, 1.0*transitionOrigin.Y);
75-
var radius = Math.Sqrt(Math.Pow(ActualWidth*horizontalProportion, 2) + Math.Pow(ActualHeight*verticalProportion, 2));
76-
77-
var scaleTransform = new ScaleTransform(0, 0);
78-
var translateTransform = new TranslateTransform(ActualWidth*transitionOrigin.X, ActualHeight*transitionOrigin.Y);
79-
var transformGroup = new TransformGroup();
80-
transformGroup.Children.Add(scaleTransform);
81-
transformGroup.Children.Add(translateTransform);
82-
var ellipseGeomotry = new EllipseGeometry()
83-
{
84-
RadiusX = radius,
85-
RadiusY = radius,
86-
Transform = transformGroup
87-
};
88-
Clip = ellipseGeomotry;
89-
90-
var zeroKeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
91-
var endKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(400));
92-
93-
var scaleAnimation = new DoubleAnimationUsingKeyFrames();
94-
scaleAnimation.Completed += ScaleAnimationOnCompleted;
95-
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, zeroKeyTime));
96-
scaleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, endKeyTime));
97-
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
98-
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
99-
}
100-
101-
private void ScaleAnimationOnCompleted(object sender, EventArgs eventArgs)
102-
{
103-
Clip = null;
104-
OnInTransitionFinished(new RoutedEventArgs(InTransitionFinished) { Source = this });
105-
}
66+
}
10667
}
10768
}

0 commit comments

Comments
 (0)