Skip to content

Commit 12533c3

Browse files
committed
closing animation. fixes #139
1 parent a80b805 commit 12533c3

File tree

3 files changed

+99
-25
lines changed

3 files changed

+99
-25
lines changed

MainDemo.Wpf/Trees.xaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
</TreeView>
113113
<materialDesign:PopupBox Grid.Row="1"
114114
Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
115-
PlacementMode="LeftAndAlignMiddles"
115+
PlacementMode="LeftAndAlignMiddles"
116+
UnfurlOrientation="Horizontal"
116117
ToolTip="Manage items"
117118
Margin="0 0 10 10"
118119
HorizontalAlignment="Right" VerticalAlignment="Bottom">

MaterialDesignThemes.Wpf/PopupBox.cs

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,8 @@ private static void IsPopupOpenPropertyChangedCallback(DependencyObject dependen
241241
Mouse.Capture(null);
242242
}
243243

244-
if (newValue)
245-
popupBox.AnimateChildren();
246244

245+
popupBox.AnimateChildrenIn(!newValue);
247246
popupBox._popup?.RefreshPosition();
248247

249248
VisualStateManager.GoToState(popupBox, newValue ? PopupIsOpenStateName : PopupIsClosedStateName, true);
@@ -299,6 +298,21 @@ public PopupBoxPopupMode PopupMode
299298
set { SetValue(PopupModeProperty, value); }
300299
}
301300

301+
/// <summary>
302+
/// Get or sets how to unfurl controls when opening the popups. Only child elements of type <see cref="ButtonBase"/> are animated.
303+
/// </summary>
304+
public static readonly DependencyProperty UnfurlOrientationProperty = DependencyProperty.Register(
305+
"UnfurlOrientation", typeof (Orientation), typeof (PopupBox), new PropertyMetadata(Orientation.Vertical));
306+
307+
/// <summary>
308+
/// Gets or sets how to unfurl controls when opening the popups. Only child elements of type <see cref="ButtonBase"/> are animated.
309+
/// </summary>
310+
public Orientation UnfurlOrientation
311+
{
312+
get { return (Orientation) GetValue(UnfurlOrientationProperty); }
313+
set { SetValue(UnfurlOrientationProperty, value); }
314+
}
315+
302316
/// <summary>
303317
/// Framework use. Provides the method used to position the popup.
304318
/// </summary>
@@ -444,56 +458,110 @@ private CustomPopupPlacement[] GetPopupPlacement(Size popupSize, Size targetSize
444458
return new[] {new CustomPopupPlacement(point, PopupPrimaryAxis.Horizontal)};
445459
}
446460

447-
private void AnimateChildren()
461+
private void AnimateChildrenIn(bool reverse)
448462
{
449463
if (_popupContentControl == null) return;
450464
if (VisualTreeHelper.GetChildrenCount(_popupContentControl) != 1) return;
451465
var contentPresenter = VisualTreeHelper.GetChild(_popupContentControl, 0) as ContentPresenter;
452466

453467
var controls = contentPresenter.VisualDepthFirstTraversal().OfType<ButtonBase>();
454-
double translateYFrom;
455-
if (PlacementMode == PopupBoxPlacementMode.TopAndAlignCentres
456-
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignLeftEdges
457-
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignRightEdges
458-
|| PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges
459-
|| PlacementMode == PopupBoxPlacementMode.RightAndAlignBottomEdges)
468+
double translateCoordinateFrom;
469+
if ((PlacementMode == PopupBoxPlacementMode.TopAndAlignCentres
470+
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignLeftEdges
471+
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignRightEdges
472+
|| PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges
473+
|| PlacementMode == PopupBoxPlacementMode.RightAndAlignBottomEdges
474+
|| (UnfurlOrientation == Orientation.Horizontal &&
475+
(
476+
PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges
477+
|| PlacementMode == PopupBoxPlacementMode.LeftAndAlignMiddles
478+
|| PlacementMode == PopupBoxPlacementMode.LeftAndAlignTopEdges
479+
))
480+
))
460481
{
461482
controls = controls.Reverse();
462-
translateYFrom = 40;
483+
translateCoordinateFrom = 80;
463484
}
464485
else
465-
translateYFrom = -40;
486+
translateCoordinateFrom = -80;
487+
488+
var translateCoordinatePath =
489+
"(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform."
490+
+ (UnfurlOrientation == Orientation.Horizontal ? "X)" : "Y)");
491+
492+
var sineEase = new SineEase();
466493

467494
var i = 0;
468495
foreach (var uiElement in controls)
469-
{
496+
{
497+
var deferredStart = i++*20;
498+
var deferredEnd = deferredStart+200.0;
499+
500+
var absoluteZeroKeyTime = KeyTime.FromPercent(0.0);
501+
var deferredStartKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(deferredStart));
502+
var deferredEndKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(deferredEnd));
503+
504+
var elementTranslateCoordinateFrom = translateCoordinateFrom * i;
505+
var translateTransform = new TranslateTransform(
506+
UnfurlOrientation == Orientation.Vertical ? 0 : elementTranslateCoordinateFrom,
507+
UnfurlOrientation == Orientation.Vertical ? elementTranslateCoordinateFrom : 0);
508+
470509
var transformGroup = new TransformGroup
471-
{
510+
{
472511
Children = new TransformCollection(new Transform[]
473512
{
474-
new ScaleTransform(.5, .5),
475-
new TranslateTransform(0, translateYFrom)
513+
new ScaleTransform(0, 0),
514+
translateTransform
476515
})
477516
};
478517
uiElement.SetCurrentValue(RenderTransformOriginProperty, new Point(.5, .5));
479518
uiElement.RenderTransform = transformGroup;
480519

481-
var scaleXAnimation = new DoubleAnimation(.5, 1, new Duration(TimeSpan.FromMilliseconds(100)));
520+
var opacityAnimation = new DoubleAnimationUsingKeyFrames();
521+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase));
522+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase));
523+
opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, deferredEndKeyTime, sineEase));
524+
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath("Opacity"));
525+
Storyboard.SetTarget(opacityAnimation, uiElement);
526+
527+
var scaleXAnimation = new DoubleAnimationUsingKeyFrames();
528+
scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase));
529+
scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase));
530+
scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, deferredEndKeyTime, sineEase));
482531
Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
483532
Storyboard.SetTarget(scaleXAnimation, uiElement);
484-
var scaleYAnimation = new DoubleAnimation(.5, 1, new Duration(TimeSpan.FromMilliseconds(100)));
533+
534+
var scaleYAnimation = new DoubleAnimationUsingKeyFrames();
535+
scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase));
536+
scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase));
537+
scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, deferredEndKeyTime, sineEase));
485538
Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
486539
Storyboard.SetTarget(scaleYAnimation, uiElement);
487-
var translateYAnimation = new DoubleAnimation(translateYFrom, 0, new Duration(TimeSpan.FromMilliseconds(100)));
488-
Storyboard.SetTargetProperty(translateYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"));
489-
Storyboard.SetTarget(translateYAnimation, uiElement);
540+
541+
var translateCoordinateAnimation = new DoubleAnimationUsingKeyFrames();
542+
translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(elementTranslateCoordinateFrom, absoluteZeroKeyTime, sineEase));
543+
translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(elementTranslateCoordinateFrom, deferredStartKeyTime, sineEase));
544+
translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredEndKeyTime, sineEase));
545+
546+
Storyboard.SetTargetProperty(translateCoordinateAnimation, new PropertyPath(translateCoordinatePath));
547+
Storyboard.SetTarget(translateCoordinateAnimation, uiElement);
548+
490549
var storyboard = new Storyboard();
550+
storyboard.Children.Add(opacityAnimation);
491551
storyboard.Children.Add(scaleXAnimation);
492552
storyboard.Children.Add(scaleYAnimation);
493-
storyboard.Children.Add(translateYAnimation);
494-
storyboard.BeginTime = TimeSpan.FromMilliseconds(i++ * 20);
553+
storyboard.Children.Add(translateCoordinateAnimation);
554+
555+
if (reverse)
556+
{
557+
storyboard.AutoReverse = true;
558+
storyboard.Begin();
559+
storyboard.Seek(TimeSpan.FromMilliseconds(deferredEnd));
560+
storyboard.Resume();
495561

496-
storyboard.Begin();
562+
}
563+
else
564+
storyboard.Begin();
497565
}
498566
}
499567

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PopupBox.xaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@
202202
</Storyboard>
203203
<Storyboard x:Key="Close">
204204
<DoubleAnimation Storyboard.TargetName="PART_PopupContentControl" Storyboard.TargetProperty="Opacity"
205-
Duration="0:0:0.1">
205+
Duration="0:0:0.8">
206206
<DoubleAnimation.EasingFunction>
207207
<SineEase EasingMode="EaseInOut" />
208208
</DoubleAnimation.EasingFunction>
@@ -311,6 +311,11 @@
311311
</Viewbox>
312312
</Setter.Value>
313313
</Setter>
314+
<Style.Triggers>
315+
<Trigger Property="UnfurlOrientation" Value="Horizontal">
316+
<Setter Property="ToolTipService.Placement" Value="Custom" />
317+
</Trigger>
318+
</Style.Triggers>
314319
</Style>
315320

316321
<Style TargetType="{x:Type wpf:PopupBox}"

0 commit comments

Comments
 (0)