Skip to content
Browse files

页面旋转效果

  • Loading branch information...
1 parent ca96302 commit 34680aab39488688f1fac23d88bfcd84d2a9c3ef @zcbenz committed Mar 3, 2012
View
3 App.xaml.cs
@@ -143,7 +143,8 @@ private void InitializePhoneApplication()
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
- RootFrame = new TransitionFrame();
+ RootFrame = new Delay.HybridOrientationChangesFrame();
+ ((Delay.HybridOrientationChangesFrame)RootFrame).Duration = TimeSpan.FromSeconds(0.8);
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
View
2 BoardPage.xaml
@@ -10,7 +10,7 @@
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
- SupportedOrientations="Portrait" Orientation="Portrait"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
d:DataContext="{d:DesignData SampleData/CurrentBoardViewModelSampleData.xaml}"
shell:SystemTray.IsVisible="True"
View
330 DynamicOrientationChanges/AnimateOrientationChangesFrame.cs
@@ -0,0 +1,330 @@
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+// This code released under the terms of the Microsoft Public License
+// (Ms-PL, http://opensource.org/licenses/ms-pl.html).
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using Microsoft.Phone.Controls;
+
+namespace Delay
+{
+ /// <summary>
+ /// PhoneApplicationFrame subclass that animates device orientation changes.
+ /// </summary>
+ public class AnimateOrientationChangesFrame : TransitionFrame
+ {
+ /// <summary>
+ /// Stores the Transform used to do the rotation.
+ /// </summary>
+ private readonly RotateTransform _rotateTransform = new RotateTransform();
+
+ /// <summary>
+ /// Stores the Transform used for centering the visuals.
+ /// </summary>
+ private readonly TranslateTransform _translateTransform = new TranslateTransform();
+
+ /// <summary>
+ /// Stores the Storyboard used to change the Progress value.
+ /// </summary>
+ private readonly Storyboard _progressStoryboard = new Storyboard();
+
+ /// <summary>
+ /// Stores the Animation used to change the Progress value.
+ /// </summary>
+ private readonly DoubleAnimation _progressAnimation = new DoubleAnimation();
+
+ /// <summary>
+ /// Stores the "from" state.
+ /// </summary>
+ private readonly OrientationState _from = new OrientationState();
+
+ /// <summary>
+ /// Stores the "to" state.
+ /// </summary>
+ private readonly OrientationState _to = new OrientationState();
+
+ /// <summary>
+ /// Stores a reference to the "ClientArea" template part.
+ /// </summary>
+ private UIElement _clientArea;
+
+ /// <summary>
+ /// Stores the last computed size from OnProgressChanged.
+ /// </summary>
+ private Size _lastSize;
+
+ /// <summary>
+ /// Stores a flag indicating whether the SizeChanged event has been handled yet.
+ /// </summary>
+ private bool _handledSizeChanged;
+
+ /// <summary>
+ /// Initializes a new instance of the AnimateOrientationChangesFrame class.
+ /// </summary>
+ public AnimateOrientationChangesFrame()
+ {
+ // Find existing "offset transform" and take it over (if possible) to support SIP raise/lower
+ var transformGroup = new TransformGroup();
+ var oldTransformGroup = RenderTransform as TransformGroup;
+ if ((null != oldTransformGroup) && (3 <= oldTransformGroup.Children.Count))
+ {
+ var offsetTransform = oldTransformGroup.Children[0] as TranslateTransform;
+ if (null != offsetTransform)
+ {
+ transformGroup.Children.Add(offsetTransform);
+ }
+ }
+ // Add custom transforms
+ transformGroup.Children.Add(_rotateTransform);
+ transformGroup.Children.Add(_translateTransform);
+ // Replace existing transform(s)
+ RenderTransform = transformGroup;
+
+ // Set up animation
+ _progressAnimation.From = 0;
+ _progressAnimation.To = 1;
+ Storyboard.SetTarget(_progressAnimation, this);
+ Storyboard.SetTargetProperty(_progressAnimation, new PropertyPath("Progress"));
+ _progressStoryboard.Children.Add(_progressAnimation);
+
+ // Initialize variables
+ EasingFunction = new QuarticEase(); // Initialized here to avoid a single shared instance
+
+ // Hook events
+ SizeChanged += new SizeChangedEventHandler(HandleSizeChanged);
+ OrientationChanged += new EventHandler<OrientationChangedEventArgs>(HandleOrientationChanged);
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether animation is enabled.
+ /// </summary>
+ public bool IsAnimationEnabled
+ {
+ get { return (bool)GetValue(IsAnimationEnabledProperty); }
+ set { SetValue(IsAnimationEnabledProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the IsAnimationEnabled DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty IsAnimationEnabledProperty =
+ DependencyProperty.Register("IsAnimationEnabled", typeof(bool), typeof(AnimateOrientationChangesFrame), new PropertyMetadata(true));
+
+ /// <summary>
+ /// Gets or sets a value indicating the duration of the orientation change animation.
+ /// </summary>
+ public TimeSpan Duration
+ {
+ get { return (TimeSpan)GetValue(DurationProperty); }
+ set { SetValue(DurationProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the Duration DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty DurationProperty =
+ DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(AnimateOrientationChangesFrame), new PropertyMetadata(TimeSpan.FromSeconds(0.4)));
+
+ /// <summary>
+ /// Gets or sets a value indicating the IEasingFunction to use for the orientation change animation.
+ /// </summary>
+ public IEasingFunction EasingFunction
+ {
+ get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
+ set { SetValue(EasingFunctionProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the EasingFunction DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty EasingFunctionProperty =
+ DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(AnimateOrientationChangesFrame), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Identifies the Progress DependencyProperty.
+ /// </summary>
+ private static readonly DependencyProperty ProgressProperty =
+ DependencyProperty.Register("Progress", typeof(double), typeof(AnimateOrientationChangesFrame), new PropertyMetadata(0.0, OnProgressChanged));
+ /// <summary>
+ /// Handles changes to the Progress property.
+ /// </summary>
+ /// <param name="o">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private static void OnProgressChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
+ {
+ ((AnimateOrientationChangesFrame)o).OnProgressChanged(/*(double)e.OldValue,*/ (double)e.NewValue);
+ }
+ /// <summary>
+ /// Handles changes to the Progress property.
+ /// </summary>
+ /// <param name="newValue">New value.</param>
+ private void OnProgressChanged(/*double oldValue,*/ double newValue)
+ {
+ // Update rotation
+ _rotateTransform.Angle = _from.Angle + (newValue * (_to.Angle - _from.Angle));
+ // Update translation (to center things)
+ var width = _from.Width + (newValue * (_to.Width - _from.Width));
+ var height = _from.Height + (newValue * (_to.Height - _from.Height));
+ var transformBounds = _rotateTransform.TransformBounds(new Rect(0, 0, width, height));
+ _translateTransform.X = ((ActualWidth - transformBounds.Width) / 2) - transformBounds.Left;
+ _translateTransform.Y = ((ActualHeight - transformBounds.Height) / 2) - transformBounds.Top;
+ // Invalidate only if size has changed
+ var size = new Size(Math.Round(width), Math.Round(height));
+ if (size != _lastSize)
+ {
+ _lastSize = size;
+ InvalidateMeasure();
+ }
+ }
+
+ /// <summary>
+ /// Called when the element's Template changes.
+ /// </summary>
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ // Get the template part
+ _clientArea = base.GetTemplateChild("ClientArea") as UIElement;
+ }
+
+ /// <summary>
+ /// Handles the SizeChanged event.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private void HandleSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ // Capture new size
+ _from.Width = e.NewSize.Width;
+ _from.Height = e.NewSize.Height;
+ _lastSize = e.NewSize;
+
+ // Measure/Arrange can be called before the SizeChanged event fires
+ InvalidateMeasure();
+
+ // Record the method call and re-run any "early" orientation changes
+ _handledSizeChanged = true;
+ HandleOrientationChanged(null, new OrientationChangedEventArgs(Orientation));
+ }
+
+ /// <summary>
+ /// Handles the OrientationChanged event.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "PageOrientation", Justification = "Spelled correctly.")]
+ private void HandleOrientationChanged(object sender, OrientationChangedEventArgs e)
+ {
+ if (!_handledSizeChanged)
+ {
+ // ActualWidth, ActualHeight, and _lastSize aren't valid yet
+ return;
+ }
+
+ // Capture current/before angle and size
+ _from.Angle = _rotateTransform.Angle;
+ _from.Width = _lastSize.Width;
+ _from.Height = _lastSize.Height;
+ _progressStoryboard.Stop();
+
+ // Determine new angle
+ switch (e.Orientation)
+ {
+ case PageOrientation.PortraitUp:
+ _to.Angle = 0;
+ break;
+ case PageOrientation.LandscapeLeft:
+ _to.Angle = 90;
+ break;
+ case PageOrientation.LandscapeRight:
+ _to.Angle = -90;
+ break;
+ case PageOrientation.PortraitDown:
+ _to.Angle = 180;
+ break;
+ default:
+ throw new NotSupportedException("Unknown PageOrientation value.");
+ }
+
+ // Determine new size
+ var actualWidth = ActualWidth;
+ var actualHeight = ActualHeight;
+ var toPortrait = (0 == (_to.Angle % 180));
+ _to.Width = toPortrait ? actualWidth : actualHeight;
+ _to.Height = toPortrait ? actualHeight : actualWidth;
+
+ if (IsAnimationEnabled && (null != sender))
+ {
+ // Animate the rotation
+ _progressAnimation.Duration = Duration;
+ _progressAnimation.EasingFunction = EasingFunction;
+ _progressStoryboard.Begin();
+ }
+ else
+ {
+ // Snap to the rotation (with guaranteed property change)
+ SetValue(ProgressProperty, 0.0);
+ SetValue(ProgressProperty, 1.0);
+ }
+ }
+
+ /// <summary>
+ /// Handles measuring the children of this element.
+ /// </summary>
+ /// <param name="availableSize">Available size.</param>
+ /// <returns>Desired size.</returns>
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ if (null != _clientArea)
+ {
+ // Adjust measure size to transition size
+ var newValue = (double)GetValue(ProgressProperty);
+ var width = _from.Width + (newValue * (_to.Width - _from.Width));
+ var height = _from.Height + (newValue * (_to.Height - _from.Height));
+ _clientArea.Measure(new Size(width, height));
+ }
+ // Return default size
+ return availableSize;
+ }
+
+ /// <summary>
+ /// Handles arranging the children of this element.
+ /// </summary>
+ /// <param name="finalSize">Size to arrange to.</param>
+ /// <returns>Used size.</returns>
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ if (null != _clientArea)
+ {
+ // Adjust arrange size to transition size
+ var newValue = (double)GetValue(ProgressProperty);
+ var width = _from.Width + (newValue * (_to.Width - _from.Width));
+ var height = _from.Height + (newValue * (_to.Height - _from.Height));
+ _clientArea.Arrange(new Rect(0, 0, width, height));
+ }
+ // Return default size
+ return finalSize;
+ }
+
+ /// <summary>
+ /// Stores state variables for orientation changes.
+ /// </summary>
+ private class OrientationState
+ {
+ /// <summary>
+ /// Gets or sets the Width.
+ /// </summary>
+ public double Width { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Height.
+ /// </summary>
+ public double Height { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Angle.
+ /// </summary>
+ public double Angle { get; set; }
+ }
+ }
+}
View
183 DynamicOrientationChanges/FadeOrientationChangesFrame.cs
@@ -0,0 +1,183 @@
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+// This code released under the terms of the Microsoft Public License
+// (Ms-PL, http://opensource.org/licenses/ms-pl.html).
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+
+namespace Delay
+{
+ /// <summary>
+ /// PhoneApplicationFrame subclass that fades between device orientation changes.
+ /// </summary>
+ public class FadeOrientationChangesFrame : TransitionFrame
+ {
+ /// <summary>
+ /// Stores the previous orientation.
+ /// </summary>
+ private PageOrientation _previousOrientation = PageOrientation.PortraitUp;
+
+ /// <summary>
+ /// Stores the Popup for displaying the "before" content.
+ /// </summary>
+ private Popup _popup = new Popup();
+
+ /// <summary>
+ /// Stores the Storyboard used to animate the transition.
+ /// </summary>
+ private Storyboard _storyboard = new Storyboard();
+
+ /// <summary>
+ /// Stores the Timeline used to perform the transition.
+ /// </summary>
+ private DoubleAnimation _animation = new DoubleAnimation { From = 1, To = 0 };
+
+ /// <summary>
+ /// Initializes a new instance of the FadeOrientationChangesFrame class.
+ /// </summary>
+ public FadeOrientationChangesFrame()
+ {
+ // Set up animation
+ Storyboard.SetTargetProperty(_animation, new PropertyPath(UIElement.OpacityProperty));
+ _storyboard.Children.Add(_animation);
+ _storyboard.Completed += new EventHandler(HandleStoryboardCompleted);
+
+ // Initialize variables
+ EasingFunction = new QuadraticEase(); // Initialized here to avoid a single shared instance
+
+ // Hook events
+ OrientationChanged += new EventHandler<OrientationChangedEventArgs>(HandleOrientationChanged);
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether animation is enabled.
+ /// </summary>
+ public bool IsAnimationEnabled
+ {
+ get { return (bool)GetValue(IsAnimationEnabledProperty); }
+ set { SetValue(IsAnimationEnabledProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the IsAnimationEnabled DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty IsAnimationEnabledProperty =
+ DependencyProperty.Register("IsAnimationEnabled", typeof(bool), typeof(FadeOrientationChangesFrame), new PropertyMetadata(true));
+
+ /// <summary>
+ /// Gets or sets a value indicating the duration of the orientation change animation.
+ /// </summary>
+ public TimeSpan Duration
+ {
+ get { return (TimeSpan)GetValue(DurationProperty); }
+ set { SetValue(DurationProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the Duration DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty DurationProperty =
+ DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(FadeOrientationChangesFrame), new PropertyMetadata(TimeSpan.FromSeconds(0.4)));
+
+ /// <summary>
+ /// Gets or sets a value indicating the IEasingFunction to use for the orientation change animation.
+ /// </summary>
+ public IEasingFunction EasingFunction
+ {
+ get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
+ set { SetValue(EasingFunctionProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the EasingFunction DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty EasingFunctionProperty =
+ DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(FadeOrientationChangesFrame), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Handles the OrientationChanged event.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private void HandleOrientationChanged(object sender, OrientationChangedEventArgs e)
+ {
+ // Stop/complete Storyboard in case it's active
+ _storyboard.Stop();
+ HandleStoryboardCompleted(null, null);
+
+ if (IsAnimationEnabled)
+ {
+ // Get "before" width/height
+ bool normal = PageOrientation.Portrait == (PageOrientation.Portrait & _previousOrientation);
+ var width = normal ? ActualWidth : ActualHeight;
+ var height = normal ? ActualHeight : ActualWidth;
+
+ // Capture "before" visuals in a WriteableBitmap
+ var writeableBitmap = new WriteableBitmap((int)width, (int)height);
+ writeableBitmap.Render(this, null);
+ writeableBitmap.Invalidate();
+
+ // Create transforms for "before" content
+ var transforms = new TransformGroup();
+ if (_previousOrientation == PageOrientation.LandscapeLeft)
+ {
+ transforms.Children.Add(new RotateTransform { Angle = 90 });
+ transforms.Children.Add(new TranslateTransform { X = ActualWidth });
+ }
+ else if (_previousOrientation == PageOrientation.LandscapeRight)
+ {
+ transforms.Children.Add(new RotateTransform { Angle = -90 });
+ transforms.Children.Add(new TranslateTransform { Y = ActualHeight });
+ }
+
+ // Create content with default background and WriteableBitmap overlay for "before"
+ var container = new Grid
+ {
+ Width = width,
+ Height = height,
+ Background = (Brush)Application.Current.Resources["PhoneBackgroundBrush"],
+ RenderTransform = transforms,
+ IsHitTestVisible = false,
+ };
+ var content = new Rectangle
+ {
+ Fill = new ImageBrush
+ {
+ ImageSource = writeableBitmap,
+ Stretch = Stretch.None,
+ }
+ };
+ container.Children.Add(content);
+
+ // Configure Popup for displaying "before" content
+ _popup.Child = container;
+ _popup.IsOpen = true;
+
+ // Update and play the animation to fade from "before" to "after"
+ Storyboard.SetTarget(_animation, container);
+ _animation.Duration = Duration;
+ _animation.EasingFunction = EasingFunction;
+ _storyboard.Begin();
+ }
+
+ // Save current orientation for next time
+ _previousOrientation = e.Orientation;
+ }
+
+ /// <summary>
+ /// Handles the completion of the Storyboard.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private void HandleStoryboardCompleted(object sender, EventArgs e)
+ {
+ // Remove and clear Popup
+ _popup.IsOpen = false;
+ _popup.Child = null;
+ }
+ }
+}
View
261 DynamicOrientationChanges/HybridOrientationChangesFrame.cs
@@ -0,0 +1,261 @@
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+// This code released under the terms of the Microsoft Public License
+// (Ms-PL, http://opensource.org/licenses/ms-pl.html).
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+
+namespace Delay
+{
+ /// <summary>
+ /// PhoneApplicationFrame subclass that animates and fades between device orientation changes.
+ /// </summary>
+ public class HybridOrientationChangesFrame : TransitionFrame
+ {
+ /// <summary>
+ /// Stores the previous orientation.
+ /// </summary>
+ private PageOrientation _previousOrientation = PageOrientation.PortraitUp;
+
+ /// <summary>
+ /// Stores the Popup for displaying the "before" content.
+ /// </summary>
+ private Popup _popup = new Popup();
+
+ /// <summary>
+ /// Stores the Storyboard used to animate the transition.
+ /// </summary>
+ private Storyboard _storyboard = new Storyboard();
+
+ /// <summary>
+ /// Stores the Timeline used to perform the "before" fade.
+ /// </summary>
+ private DoubleAnimation _beforeOpacityAnimation = new DoubleAnimation { From = 1, To = 0 };
+
+ /// <summary>
+ /// Stores the Timeline used to perform the "after" fade.
+ /// </summary>
+ private DoubleAnimation _afterOpacityAnimation = new DoubleAnimation { From = 0, To = 1 };
+
+ /// <summary>
+ /// Stores the Timeline used to perform the "before" rotation.
+ /// </summary>
+ private DoubleAnimation _beforeRotationAnimation = new DoubleAnimation();
+
+ /// <summary>
+ /// Stores the Timeline used to perform the "before" rotation.
+ /// </summary>
+ private DoubleAnimation _afterRotationAnimation = new DoubleAnimation();
+
+ /// <summary>
+ /// Stores the Transform used to create the "after" rotation.
+ /// </summary>
+ private RotateTransform _afterRotateTransform = new RotateTransform();
+
+ /// <summary>
+ /// Initializes a new instance of the HybridOrientationChangesFrame class.
+ /// </summary>
+ public HybridOrientationChangesFrame()
+ {
+ // Set up animations
+ Storyboard.SetTargetProperty(_beforeOpacityAnimation, new PropertyPath(UIElement.OpacityProperty));
+ _storyboard.Children.Add(_beforeOpacityAnimation);
+ Storyboard.SetTargetProperty(_afterOpacityAnimation, new PropertyPath(UIElement.OpacityProperty));
+ _storyboard.Children.Add(_afterOpacityAnimation);
+ Storyboard.SetTargetProperty(_beforeRotationAnimation, new PropertyPath(RotateTransform.AngleProperty));
+ _storyboard.Children.Add(_beforeRotationAnimation);
+ Storyboard.SetTargetProperty(_afterRotationAnimation, new PropertyPath(RotateTransform.AngleProperty));
+ _storyboard.Children.Add(_afterRotationAnimation);
+ _storyboard.Completed += new EventHandler(HandleStoryboardCompleted);
+
+ // Initialize variables
+ EasingFunction = new QuadraticEase(); // Initialized here to avoid a single shared instance
+
+ // Add custom transform to end of existing group
+ var transformGroup = RenderTransform as TransformGroup;
+ if (null != transformGroup)
+ {
+ transformGroup.Children.Add(_afterRotateTransform);
+ }
+
+ // Hook events
+ OrientationChanged += new EventHandler<OrientationChangedEventArgs>(HandleOrientationChanged);
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether animation is enabled.
+ /// </summary>
+ public bool IsAnimationEnabled
+ {
+ get { return (bool)GetValue(IsAnimationEnabledProperty); }
+ set { SetValue(IsAnimationEnabledProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the IsAnimationEnabled DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty IsAnimationEnabledProperty =
+ DependencyProperty.Register("IsAnimationEnabled", typeof(bool), typeof(HybridOrientationChangesFrame), new PropertyMetadata(true));
+
+ /// <summary>
+ /// Gets or sets a value indicating the duration of the orientation change animation.
+ /// </summary>
+ public TimeSpan Duration
+ {
+ get { return (TimeSpan)GetValue(DurationProperty); }
+ set { SetValue(DurationProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the Duration DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty DurationProperty =
+ DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(HybridOrientationChangesFrame), new PropertyMetadata(TimeSpan.FromSeconds(0.4)));
+
+ /// <summary>
+ /// Gets or sets a value indicating the IEasingFunction to use for the orientation change animation.
+ /// </summary>
+ public IEasingFunction EasingFunction
+ {
+ get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
+ set { SetValue(EasingFunctionProperty, value); }
+ }
+ /// <summary>
+ /// Identifies the EasingFunction DependencyProperty.
+ /// </summary>
+ public static readonly DependencyProperty EasingFunctionProperty =
+ DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(HybridOrientationChangesFrame), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Handles the OrientationChanged event.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private void HandleOrientationChanged(object sender, OrientationChangedEventArgs e)
+ {
+ // Stop/complete Storyboard in case it's active
+ _storyboard.Stop();
+ HandleStoryboardCompleted(null, null);
+
+ if (IsAnimationEnabled)
+ {
+ // Capture device width/height
+ var actualWidth = ActualWidth;
+ var actualHeight = ActualHeight;
+
+ // Get "before" width/height
+ bool normal = PageOrientation.Portrait == (PageOrientation.Portrait & _previousOrientation);
+ var width = normal ? actualWidth : actualHeight;
+ var height = normal ? actualHeight : actualWidth;
+
+ // Capture "before" visuals in a WriteableBitmap
+ var writeableBitmap = new WriteableBitmap((int)width, (int)height);
+ writeableBitmap.Render(this, null);
+ writeableBitmap.Invalidate();
+
+ // Create transforms for "before" content
+ var beforeTranslateTransform = new TranslateTransform();
+ var beforeRotateTransform = new RotateTransform { CenterX = actualWidth / 2, CenterY = actualHeight / 2 };
+ var beforeTransforms = new TransformGroup();
+ beforeTransforms.Children.Add(beforeTranslateTransform);
+ beforeTransforms.Children.Add(beforeRotateTransform);
+
+ // Configure transforms for "before" content
+ var translateDelta = (actualHeight - actualWidth) / 2;
+ var beforeAngle = 0.0;
+ if (PageOrientation.LandscapeLeft == _previousOrientation)
+ {
+ beforeAngle = -90;
+ beforeTranslateTransform.X = -translateDelta;
+ beforeTranslateTransform.Y = translateDelta;
+ }
+ else if (PageOrientation.LandscapeRight == _previousOrientation)
+ {
+ beforeAngle = 90;
+ beforeTranslateTransform.X = -translateDelta;
+ beforeTranslateTransform.Y = translateDelta;
+ }
+ beforeRotateTransform.Angle = -beforeAngle;
+
+ // Configure for "after" content
+ var afterAngle = 0.0;
+ if (PageOrientation.LandscapeLeft == e.Orientation)
+ {
+ afterAngle = -90;
+ }
+ else if (PageOrientation.LandscapeRight == e.Orientation)
+ {
+ afterAngle = 90;
+ }
+ _afterRotateTransform.CenterX = actualWidth / 2;
+ _afterRotateTransform.CenterY = actualHeight / 2;
+
+ // Create content with default background and WriteableBitmap overlay for "before"
+ var container = new Grid
+ {
+ Width = width,
+ Height = height,
+ Background = (Brush)Application.Current.Resources["PhoneBackgroundBrush"],
+ RenderTransform = beforeTransforms,
+ IsHitTestVisible = false,
+ };
+ var content = new Rectangle
+ {
+ Fill = new ImageBrush
+ {
+ ImageSource = writeableBitmap,
+ Stretch = Stretch.None,
+ }
+ };
+ container.Children.Add(content);
+
+ // Configure Popup for displaying "before" content
+ _popup.Child = container;
+ _popup.IsOpen = true;
+
+ // Update animations to fade from "before" to "after"
+ Storyboard.SetTarget(_beforeOpacityAnimation, container);
+ _beforeOpacityAnimation.Duration = Duration;
+ _beforeOpacityAnimation.EasingFunction = EasingFunction;
+ Storyboard.SetTarget(_afterOpacityAnimation, this);
+ _afterOpacityAnimation.Duration = Duration;
+ _afterOpacityAnimation.EasingFunction = EasingFunction;
+
+ // Update animations to rotate from "before" to "after"
+ Storyboard.SetTarget(_beforeRotationAnimation, beforeRotateTransform);
+ _beforeRotationAnimation.From = beforeRotateTransform.Angle;
+ _beforeRotationAnimation.To = _beforeRotationAnimation.From + (beforeAngle - afterAngle);
+ _beforeRotationAnimation.Duration = Duration;
+ _beforeRotationAnimation.EasingFunction = EasingFunction;
+ Storyboard.SetTarget(_afterRotationAnimation, _afterRotateTransform);
+ _afterRotationAnimation.From = -(beforeAngle - afterAngle);
+ _afterRotationAnimation.To = 0;
+ _afterRotationAnimation.Duration = Duration;
+ _afterRotationAnimation.EasingFunction = EasingFunction;
+
+ // Play the animations
+ _storyboard.Begin();
+ }
+
+ // Save current orientation for next time
+ _previousOrientation = e.Orientation;
+ }
+
+ /// <summary>
+ /// Handles the completion of the Storyboard.
+ /// </summary>
+ /// <param name="sender">Event source.</param>
+ /// <param name="e">Event arguments.</param>
+ private void HandleStoryboardCompleted(object sender, EventArgs e)
+ {
+ // Remove and clear Popup
+ _popup.IsOpen = false;
+ _popup.Child = null;
+ }
+ }
+}
View
2 TopicPage.xaml
@@ -10,7 +10,7 @@
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
- SupportedOrientations="Portrait" Orientation="Portrait"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
d:DataContext="{d:DesignData SampleData/CurrentTopicViewModelSampleData.xaml}">
View
4 ValueConverters/StampDateConverter.cs
@@ -24,9 +24,9 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
if (date.Year == now.Year && date.Month == now.Month && date.Day == now.Day)
return date.ToString("HH:mm", culture);
else if (date.Year == now.Year)
- return date.ToString("m HH:mm", culture);
+ return date.ToString("MMM d HH:mm", culture);
else
- return date.ToString("y HH:mm", culture);
+ return date.ToString("y MMM d", culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
View
3 sbbs-client-wp7.csproj
@@ -68,6 +68,9 @@
<Compile Include="BoardPage.xaml.cs">
<DependentUpon>BoardPage.xaml</DependentUpon>
</Compile>
+ <Compile Include="DynamicOrientationChanges\AnimateOrientationChangesFrame.cs" />
+ <Compile Include="DynamicOrientationChanges\FadeOrientationChangesFrame.cs" />
+ <Compile Include="DynamicOrientationChanges\HybridOrientationChangesFrame.cs" />
<Compile Include="LocalCache.cs" />
<Compile Include="LoginPage.xaml.cs">
<DependentUpon>LoginPage.xaml</DependentUpon>

0 comments on commit 34680aa

Please sign in to comment.
Something went wrong with that request. Please try again.