仿windows8 开始菜单 实现HubTileBase 以及仿鲜果联播实现 PulsingTile(脉冲磁贴)
本文章将以如何实现 开始菜单上的tile 为主。
该控件代码经过测试可直接使用。

tile 在我的思路中分为了 3层。
基于ContentControl实现HeaderedContentControl 用于增加Tile种的内容标题
在HeaderedContentControl 的基础上 实现 3d变换 根据触点方向触发不同动画。
实现HubTileBase
在HubTileBase 下我们可以实现多种磁贴
如liveTile(实时反馈) MosaicTile(仿wp8 风格) PulsingTile(脉冲)等等。。
以下将以PulsingTile 代码为主 来介绍
public class HeaderedContentControl : ContentControl { public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(HeaderedContentControl), new PropertyMetadata(null)); public static readonly DependencyProperty HeaderStyleProperty = DependencyProperty.Register("HeaderStyle", typeof(Style), typeof(HeaderedContentControl), new PropertyMetadata(null)); public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(HeaderedContentControl), new PropertyMetadata(null)); public static readonly DependencyProperty HeaderTemplateSelectorProperty = DependencyProperty.Register("HeaderTemplateSelector", typeof(DataTemplateSelector), typeof(HeaderedContentControl), new PropertyMetadata(null)); public HeaderedContentControl() { this.DefaultStyleKey = typeof(HeaderedContentControl); } public object Header { get { return base.GetValue(HeaderProperty); } set { base.SetValue(HeaderProperty, value); } } public Style HeaderStyle { get { return (Style)base.GetValue(HeaderStyleProperty); } set { base.SetValue(HeaderStyleProperty, value); } } public DataTemplate HeaderTemplate { get { return (DataTemplate)base.GetValue(HeaderTemplateProperty); } set { base.SetValue(HeaderTemplateProperty, value); } } public DataTemplateSelector HeaderTemplateSelector { get { return (DataTemplateSelector)base.GetValue(HeaderTemplateSelectorProperty); } set { base.SetValue(HeaderTemplateSelectorProperty, value); } } }
public class HubTileBase : HeaderedContentControl { public static readonly DependencyProperty AccentBrushProperty = DependencyProperty.Register("AccentBrush", typeof(Brush), typeof(HubTileBase), new PropertyMetadata(null)); public static readonly DependencyProperty GroupNameProperty = DependencyProperty.Register("GroupName", typeof(string), typeof(HubTileBase), new PropertyMetadata(string.Empty)); public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(Windows.UI.Xaml.Media.ImageSource), typeof(HubTileBase), new PropertyMetadata(null)); public static readonly DependencyProperty IsFrozenProperty = DependencyProperty.Register("IsFrozen", typeof(bool), typeof(HubTileBase), new PropertyMetadata((bool)false, OnIsFrozenChanged)); public static readonly DependencyProperty OverrideDefaultStatesProperty = DependencyProperty.Register("OverrideDefaultStates", typeof(bool), typeof(HubTileBase), new PropertyMetadata((bool)false)); private PointerDirection pointerdirection; private bool pointerover; private bool pointerpressed; public static readonly DependencyProperty RotationDepthProperty = DependencyProperty.Register("RotationDepth", typeof(double), typeof(HubTileBase), new PropertyMetadata((double)20.0)); public static readonly DependencyProperty ScaleDepthProperty = DependencyProperty.Register("ScaleDepth", typeof(double), typeof(HubTileBase), new PropertyMetadata((double)0.9)); private Storyboard storyboard; public static readonly DependencyProperty TilePressDurationProperty = DependencyProperty.Register("TilePressDuration", typeof(TimeSpan), typeof(HubTileBase), new PropertyMetadata(TimeSpan.FromSeconds((double)0.1))); public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(object), typeof(HubTileBase), new PropertyMetadata(null)); public static readonly DependencyProperty TitleStyleProperty = DependencyProperty.Register("TitleStyle", typeof(Style), typeof(HubTileBase), new PropertyMetadata(null)); private Timeline BuildAnimation(PointerDirection direction) { DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); Storyboard.SetTarget(frames, this); if (direction != PointerDirection.Center) { PlaneProjection projection2 = new PlaneProjection(); projection2.CenterOfRotationZ = 0.0; PlaneProjection projection = projection2; EasingDoubleKeyFrame frame3 = new EasingDoubleKeyFrame(); frame3.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); frame3.Value = 0.0; EasingDoubleKeyFrame frame = frame3; EasingDoubleKeyFrame frame4 = new EasingDoubleKeyFrame(); frame4.KeyTime = ((KeyTime)this.TilePressDuration); EasingDoubleKeyFrame frame2 = frame4; frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); if ((direction == PointerDirection.Left) || (direction == PointerDirection.Bottom)) { frame2.Value = this.RotationDepth; } else if ((direction == PointerDirection.Top) || (direction == PointerDirection.Right)) { frame2.Value = -this.RotationDepth; } if ((direction == PointerDirection.Top) || (direction == PointerDirection.Bottom)) { Storyboard.SetTargetProperty(frames, "(UIElement.Projection).(PlaneProjection.RotationX)"); } else if ((direction == PointerDirection.Left) || (direction == PointerDirection.Right)) { Storyboard.SetTargetProperty(frames, "(UIElement.Projection).(PlaneProjection.RotationY)"); } if (direction == PointerDirection.Bottom) { projection.CenterOfRotationX = 0.5; projection.CenterOfRotationY = 0.0; } else if (direction == PointerDirection.Top) { projection.CenterOfRotationX = (0.5); projection.CenterOfRotationY = (1.0); } else if (direction == PointerDirection.Left) { projection.CenterOfRotationX = (1.0); projection.CenterOfRotationY = (0.5); } else if (direction == PointerDirection.Right) { projection.CenterOfRotationX = (0.0); projection.CenterOfRotationY = (0.5); } base.Projection = (projection); } return frames; } private Timeline BuildScaleXAnimation() { DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); Storyboard.SetTarget(frames, this); Storyboard.SetTargetProperty(frames, "(UIElement.RenderTransform).(CompositeTransform.ScaleX)"); EasingDoubleKeyFrame frame3 = new EasingDoubleKeyFrame(); frame3.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); frame3.Value = (1.0); EasingDoubleKeyFrame frame = frame3; EasingDoubleKeyFrame frame4 = new EasingDoubleKeyFrame(); frame4.KeyTime = ((KeyTime)this.TilePressDuration); frame4.Value = (this.ScaleDepth); EasingDoubleKeyFrame frame2 = frame4; frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); CompositeTransform transform = new CompositeTransform(); base.RenderTransformOrigin = (new Point(0.5, 0.5)); base.RenderTransform = (transform); return frames; } private Timeline BuildScaleYAnimation() { DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); Storyboard.SetTarget(frames, this); Storyboard.SetTargetProperty(frames, "(UIElement.RenderTransform).(CompositeTransform.ScaleY)"); EasingDoubleKeyFrame frame3 = new EasingDoubleKeyFrame(); frame3.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); frame3.Value = (1.0); EasingDoubleKeyFrame frame = frame3; EasingDoubleKeyFrame frame4 = new EasingDoubleKeyFrame(); frame4.KeyTime = ((KeyTime)this.TilePressDuration); frame4.Value = (this.ScaleDepth); EasingDoubleKeyFrame frame2 = frame4; frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); CompositeTransform transform = new CompositeTransform(); base.RenderTransform = (transform); base.RenderTransformOrigin = (new Point(0.5, 0.5)); return frames; } private void ExecutePointerReleased() { if (this.pointerpressed) { if (this.OverrideDefaultStates) { if (this.pointerover) { VisualStateManager.GoToState(this, "PointerOver", true); } else { VisualStateManager.GoToState(this, "Normal", true); } } else if (this.storyboard != null) { if (this.pointerdirection != PointerDirection.Center) { DoubleAnimationUsingKeyFrames frames = this.storyboard.Children[0] as DoubleAnimationUsingKeyFrames; if (frames != null) { EasingDoubleKeyFrame frame = frames.KeyFrames[0] as EasingDoubleKeyFrame; EasingDoubleKeyFrame frame2 = frames.KeyFrames[1] as EasingDoubleKeyFrame; frame.Value = (frame2.Value); frame2.Value = (0.0); } } else { DoubleAnimationUsingKeyFrames frames2 = this.storyboard.Children[0] as DoubleAnimationUsingKeyFrames; DoubleAnimationUsingKeyFrames frames3 = this.storyboard.Children[1] as DoubleAnimationUsingKeyFrames; if (frames2 != null) { EasingDoubleKeyFrame frame3 = frames2.KeyFrames[0] as EasingDoubleKeyFrame; EasingDoubleKeyFrame frame4 = frames2.KeyFrames[1] as EasingDoubleKeyFrame; frame3.Value = (frame4.Value); frame4.Value = (1.0); } if (frames3 != null) { EasingDoubleKeyFrame frame5 = frames3.KeyFrames[0] as EasingDoubleKeyFrame; EasingDoubleKeyFrame frame6 = frames3.KeyFrames[1] as EasingDoubleKeyFrame; frame5.Value = (frame6.Value); frame6.Value = (1.0); } } this.storyboard.Begin(); } } this.pointerpressed = false; } protected virtual void OnIsFrozenChanged(DependencyPropertyChangedEventArgs e) { } private static void OnIsFrozenChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { HubTileBase base2 = sender as HubTileBase; if (base2 != null) { base2.OnIsFrozenChanged(e); } } protected override void OnPointerEntered(PointerRoutedEventArgs e) { this.pointerover = true; VisualStateManager.GoToState(this, "PointerOver", true); base.OnPointerEntered(e); } protected override void OnPointerExited(PointerRoutedEventArgs e) { if (this.pointerpressed) { this.ExecutePointerReleased(); } this.pointerover = false; VisualStateManager.GoToState(this, "Normal", true); base.OnPointerExited(e); } protected override void OnPointerPressed(PointerRoutedEventArgs e) { this.pointerpressed = true; if (this.OverrideDefaultStates) { VisualStateManager.GoToState(this, "PointerPressed", true); } else { PointerPoint currentpoint = e.GetCurrentPoint(this); var point = currentpoint.Position; double num = base.ActualWidth / 3.0; double num2 = base.ActualHeight / 3.0; Dictionary<PointerDirection, Rect> pieces = new Dictionary<PointerDirection, Rect>(); pieces.Add(PointerDirection.TopLeft, new Rect(0.0, 0.0, num, num2)); pieces.Add(PointerDirection.Top, new Rect(num, 0.0, num, num2)); pieces.Add(PointerDirection.TopRight, new Rect(num * 2.0, 0.0, num, num2)); pieces.Add(PointerDirection.Left, new Rect(0.0, num2, num, num2)); pieces.Add(PointerDirection.Center, new Rect(num, num2, num, num2)); pieces.Add(PointerDirection.Right, new Rect(num * 2.0, num2, num, num2)); pieces.Add(PointerDirection.BottomLeft, new Rect(0.0, num2 * 2.0, num, num2)); pieces.Add(PointerDirection.Bottom, new Rect(num, num2 * 2.0, num, num2)); pieces.Add(PointerDirection.BottomRight, new Rect(num * 2.0, num2 * 2.0, num, num2)); this.pointerdirection = (from _direction in pieces.Keys where pieces[_direction].Contains(point) select _direction).FirstOrDefault(); this.storyboard = new Storyboard(); if (this.pointerdirection <= PointerDirection.Center) { if (this.pointerdirection == PointerDirection.Center) { Timeline timeline = this.BuildScaleXAnimation(); Timeline timeline2 = this.BuildScaleYAnimation(); this.storyboard.Children.Add(timeline); this.storyboard.Children.Add(timeline2); this.storyboard.Begin(); } else { Timeline timeline3 = this.BuildAnimation(this.pointerdirection); this.storyboard.Children.Add(timeline3); this.storyboard.Begin(); } } else if (this.pointerdirection == PointerDirection.TopLeft) { if (currentpoint.Position.X > currentpoint.Position.Y) { Timeline timeline4 = this.BuildAnimation(PointerDirection.Top); this.storyboard.Children.Add(timeline4); this.storyboard.Begin(); } else { Timeline timeline5 = this.BuildAnimation(PointerDirection.Left); this.storyboard.Children.Add(timeline5); this.storyboard.Begin(); } } else if (this.pointerdirection == PointerDirection.TopRight) { if (currentpoint.Position.Y > (num2 - (currentpoint.Position.X - (num * 2.0)))) { Timeline timeline6 = this.BuildAnimation(PointerDirection.Right); this.storyboard.Children.Add(timeline6); this.storyboard.Begin(); } else { Timeline timeline7 = this.BuildAnimation(PointerDirection.Top); this.storyboard.Children.Add(timeline7); this.storyboard.Begin(); } } else if (this.pointerdirection == PointerDirection.BottomLeft) { if ((currentpoint.Position.Y - (num2 * 2.0)) > (num2 - currentpoint.Position.X)) { Timeline timeline8 = this.BuildAnimation(PointerDirection.Bottom); this.storyboard.Children.Add(timeline8); this.storyboard.Begin(); } else { Timeline timeline9 = this.BuildAnimation(PointerDirection.Left); this.storyboard.Children.Add(timeline9); this.storyboard.Begin(); } } else if (currentpoint.Position.X > currentpoint.Position.Y) { Timeline timeline10 = this.BuildAnimation(PointerDirection.Right); this.storyboard.Children.Add(timeline10); this.storyboard.Begin(); } else { Timeline timeline11 = this.BuildAnimation(PointerDirection.Bottom); this.storyboard.Children.Add(timeline11); this.storyboard.Begin(); } } base.OnPointerPressed(e); } protected override void OnPointerReleased(PointerRoutedEventArgs e) { this.ExecutePointerReleased(); base.OnPointerReleased(e); } public Brush AccentBrush { get { return (Brush)base.GetValue(AccentBrushProperty); } set { base.SetValue(AccentBrushProperty, value); } } public string GroupName { get { return (string)((string)base.GetValue(GroupNameProperty)); } set { base.SetValue(GroupNameProperty, value); } } public Windows.UI.Xaml.Media.ImageSource ImageSource { get { return (Windows.UI.Xaml.Media.ImageSource)base.GetValue(ImageSourceProperty); } set { base.SetValue(ImageSourceProperty, value); } } public bool IsFrozen { get { return (bool)((bool)base.GetValue(IsFrozenProperty)); } set { base.SetValue(IsFrozenProperty, (bool)value); } } public bool OverrideDefaultStates { get { return (bool)((bool)base.GetValue(OverrideDefaultStatesProperty)); } set { base.SetValue(OverrideDefaultStatesProperty, (bool)value); } } public double RotationDepth { get { return (double)((double)base.GetValue(RotationDepthProperty)); } set { base.SetValue(RotationDepthProperty, (double)value); } } public double ScaleDepth { get { return (double)((double)base.GetValue(ScaleDepthProperty)); } set { base.SetValue(ScaleDepthProperty, (double)value); } } public TimeSpan TilePressDuration { get { return (TimeSpan)base.GetValue(TilePressDurationProperty); } set { base.SetValue(TilePressDurationProperty, value); } } public object Title { get { return base.GetValue(TitleProperty); } set { base.SetValue(TitleProperty, value); } } public Style TitleStyle { get { return (Style)base.GetValue(TitleStyleProperty); } set { base.SetValue(TitleStyleProperty, value); } } }
public static class HubTileService { private static List<WeakReference> Tiles = new List<WeakReference>(); internal static void Dequeue(HubTileBase tile) { foreach (WeakReference reference in Tiles) { if (reference.Target == tile) { Tiles.Remove(reference); break; } } } internal static void Enqueue(HubTileBase tile) { WeakReference reference = new WeakReference(tile, false); Tiles.Add(reference); } public static void Freeze(HubTileBase tile) { foreach (WeakReference reference in Tiles) { if (reference.Target == tile) { HubTileBase base2 = reference.Target as HubTileBase; base2.IsFrozen = true; break; } } } public static void Freeze(string groupname) { using (List<WeakReference>.Enumerator enumerator = Tiles.GetEnumerator()) { while (enumerator.MoveNext()) { HubTileBase base2 = enumerator.Current.Target as HubTileBase; if ((base2 != null) && (base2.GroupName == groupname)) { base2.IsFrozen = false; } } } } public static void UnFreeze(HubTileBase tile) { foreach (WeakReference reference in Tiles) { if (reference.Target == tile) { HubTileBase base2 = reference.Target as HubTileBase; base2.IsFrozen = false; break; } } } public static void UnFreeze(string groupname) { using (List<WeakReference>.Enumerator enumerator = Tiles.GetEnumerator()) { while (enumerator.MoveNext()) { HubTileBase base2 = enumerator.Current.Target as HubTileBase; if ((base2 != null) && (base2.GroupName == groupname)) { base2.IsFrozen = false; } } } } }
public enum PointerDirection { Left, Top, Right, Bottom, Center, TopLeft, TopRight, BottomLeft, BottomRight }
public class PulsingTile : HubTileBase { protected ContentPresenter PART_Content; public static readonly DependencyProperty PulseDurationProperty = DependencyProperty.Register("PulseDuration", typeof(TimeSpan), typeof(PulsingTile), new PropertyMetadata(TimeSpan.FromSeconds((double)4.0), new PropertyChangedCallback(OnValueChanged))); public static readonly DependencyProperty PulseScaleProperty = DependencyProperty.Register("PulseScale", typeof(double), typeof(PulsingTile), new PropertyMetadata((double)1.0, new PropertyChangedCallback(OnValueChanged))); private Storyboard pulseStroyboard; public static readonly DependencyProperty RadiusXProperty = DependencyProperty.Register("RadiusX", typeof(double), typeof(PulsingTile), new PropertyMetadata((double)0.0, new PropertyChangedCallback(OnValueChanged))); public static readonly DependencyProperty RadiusYProperty = DependencyProperty.Register("RadiusY", typeof(double), typeof(PulsingTile), new PropertyMetadata((double)0.0, new PropertyChangedCallback(OnValueChanged))); private Storyboard roatationStroyboard; public static readonly DependencyProperty TranslateDurationProperty = DependencyProperty.Register("TranslateDuration", typeof(TimeSpan), typeof(PulsingTile), new PropertyMetadata(TimeSpan.FromSeconds((double)4.0), new PropertyChangedCallback(OnValueChanged))); public PulsingTile() { base.DefaultStyleKey = (typeof(PulsingTile)); PulsingTile tile = this; this.Loaded += this.OnLoaded; } private void AnimateContent() { if (this.PART_Content != null) { RectangleGeometry geometry = new RectangleGeometry(); geometry.Rect = (new Rect(0.0, 0.0, base.ActualWidth, base.ActualHeight)); base.Clip = (geometry); this.PART_Content.RenderTransform = (new CompositeTransform()); this.PART_Content.RenderTransformOrigin = (new Point(0.5, 0.5)); this.PART_Content.Visibility = Windows.UI.Xaml.Visibility.Visible; DoubleAnimationUsingKeyFrames frames = this.BuildXTimeLine(this.RadiusX, this.RadiusY); DoubleAnimationUsingKeyFrames frames2 = this.BuildYTimeLine(this.RadiusX, this.RadiusY); this.roatationStroyboard = new Storyboard(); RepeatBehavior behavior = new RepeatBehavior(); behavior.Type = (RepeatBehaviorType.Forever); this.roatationStroyboard.RepeatBehavior = (behavior); this.roatationStroyboard.Children.Add(frames); this.roatationStroyboard.Children.Add(frames2); Storyboard.SetTarget(frames, this.PART_Content); Storyboard.SetTarget(frames2, this.PART_Content); Storyboard.SetTargetProperty(frames, "(UIElement.RenderTransform).(CompositeTransform.TranslateX)"); Storyboard.SetTargetProperty(frames2, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)"); DoubleAnimationUsingKeyFrames frames3 = this.BuildPulseXTimeLine(this.PulseScale); DoubleAnimationUsingKeyFrames frames4 = this.BuildPulseYTimeLine(this.PulseScale); this.pulseStroyboard = new Storyboard(); this.pulseStroyboard.AutoReverse = (true); this.pulseStroyboard.SpeedRatio = (0.4); RepeatBehavior behavior2 = new RepeatBehavior(); behavior2.Type = (RepeatBehaviorType.Forever); this.pulseStroyboard.RepeatBehavior = (behavior2); this.pulseStroyboard.Children.Add(frames3); this.pulseStroyboard.Children.Add(frames4); Storyboard.SetTarget(frames3, this.PART_Content); Storyboard.SetTarget(frames4, this.PART_Content); Storyboard.SetTargetProperty(frames3, "(UIElement.RenderTransform).(CompositeTransform.ScaleX)"); Storyboard.SetTargetProperty(frames4, "(UIElement.RenderTransform).(CompositeTransform.ScaleY)"); this.pulseStroyboard.Begin(); this.roatationStroyboard.Begin(); } } private DoubleAnimationUsingKeyFrames BuildPulseXTimeLine(double pulseScale) { TimeSpan pulseDuration = this.PulseDuration; SplineDoubleKeyFrame frame = new SplineDoubleKeyFrame(); frame.Value = (1.0); frame.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); EasingDoubleKeyFrame frame2 = new EasingDoubleKeyFrame(); frame2.Value = (pulseScale); frame2.KeyTime = (KeyTime.FromTimeSpan(this.PulseDuration)); SineEase ease = new SineEase(); ease.EasingMode = EasingMode.EaseOut; frame2.EasingFunction = (ease); DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); return frames; } private DoubleAnimationUsingKeyFrames BuildPulseYTimeLine(double pulseScale) { TimeSpan pulseDuration = this.PulseDuration; SplineDoubleKeyFrame frame = new SplineDoubleKeyFrame(); frame.Value = (1.0); frame.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); EasingDoubleKeyFrame frame2 = new EasingDoubleKeyFrame(); frame2.Value = (pulseScale); frame2.KeyTime = (KeyTime.FromTimeSpan(this.PulseDuration)); SineEase ease = new SineEase(); ease.EasingMode = EasingMode.EaseOut; frame2.EasingFunction = (ease); DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); return frames; } private DoubleAnimationUsingKeyFrames BuildXTimeLine(double radiusx, double radiusy) { TimeSpan translateDuration = this.TranslateDuration; DiscreteDoubleKeyFrame frame = new DiscreteDoubleKeyFrame(); frame.Value = (0.0); frame.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); EasingDoubleKeyFrame frame2 = new EasingDoubleKeyFrame(); frame2.Value = (radiusx); frame2.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)(translateDuration.TotalSeconds / 4.0)))); SineEase ease = new SineEase(); ease.EasingMode = EasingMode.EaseIn; frame2.EasingFunction = (ease); EasingDoubleKeyFrame frame3 = new EasingDoubleKeyFrame(); frame3.Value = (0.0); frame3.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)(translateDuration.TotalSeconds / 2.0)))); SineEase ease2 = new SineEase(); ease2.EasingMode = EasingMode.EaseInOut; frame3.EasingFunction = ease2; EasingDoubleKeyFrame frame4 = new EasingDoubleKeyFrame(); frame4.Value = (-radiusx); frame4.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)((translateDuration.TotalSeconds * 3.0) / 4.0)))); SineEase ease3 = new SineEase(); ease3.EasingMode = EasingMode.EaseIn; frame4.EasingFunction = (ease3); EasingDoubleKeyFrame frame5 = new EasingDoubleKeyFrame(); frame5.Value = (0.0); frame5.KeyTime = (KeyTime.FromTimeSpan(translateDuration)); SineEase ease4 = new SineEase(); ease4.EasingMode = EasingMode.EaseInOut; frame5.EasingFunction = (ease4); DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); frames.KeyFrames.Add(frame3); frames.KeyFrames.Add(frame4); frames.KeyFrames.Add(frame5); return frames; } private DoubleAnimationUsingKeyFrames BuildYTimeLine(double radiusx, double radiusy) { TimeSpan translateDuration = this.TranslateDuration; DiscreteDoubleKeyFrame frame = new DiscreteDoubleKeyFrame(); frame.Value = (0.0); frame.KeyTime = ((KeyTime)TimeSpan.FromSeconds((double)0.0)); EasingDoubleKeyFrame frame2 = new EasingDoubleKeyFrame(); frame2.Value = (this.RadiusY); frame2.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)(translateDuration.TotalSeconds / 4.0)))); SineEase ease = new SineEase(); ease.EasingMode = EasingMode.EaseIn; frame2.EasingFunction = (ease); EasingDoubleKeyFrame frame3 = new EasingDoubleKeyFrame(); frame3.Value = (2.0 * this.RadiusY); frame3.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)(translateDuration.TotalSeconds / 2.0)))); SineEase ease2 = new SineEase(); ease2.EasingMode = EasingMode.EaseIn; frame3.EasingFunction = (ease2); EasingDoubleKeyFrame frame4 = new EasingDoubleKeyFrame(); frame4.Value = (radiusy); frame4.KeyTime = (KeyTime.FromTimeSpan(TimeSpan.FromSeconds((double)((translateDuration.TotalSeconds * 3.0) / 4.0)))); SineEase ease3 = new SineEase(); ease3.EasingMode = EasingMode.EaseInOut; frame4.EasingFunction = (ease3); EasingDoubleKeyFrame frame5 = new EasingDoubleKeyFrame(); frame5.Value = (0.0); frame5.KeyTime = (KeyTime.FromTimeSpan(translateDuration)); SineEase ease4 = new SineEase(); ease4.EasingMode = EasingMode.EaseIn; frame5.EasingFunction = (ease4); DoubleAnimationUsingKeyFrames frames = new DoubleAnimationUsingKeyFrames(); frames.KeyFrames.Add(frame); frames.KeyFrames.Add(frame2); frames.KeyFrames.Add(frame3); frames.KeyFrames.Add(frame4); frames.KeyFrames.Add(frame5); return frames; } protected override void OnApplyTemplate() { base.OnApplyTemplate(); this.PART_Content = base.GetTemplateChild("PART_Content") as ContentPresenter; } protected override void OnIsFrozenChanged(DependencyPropertyChangedEventArgs e) { if (base.IsFrozen) { if (this.pulseStroyboard != null) { this.pulseStroyboard.Stop(); } if (this.roatationStroyboard != null) { this.roatationStroyboard.Stop(); } } else { if (this.pulseStroyboard != null) { this.pulseStroyboard.Begin(); } if (this.roatationStroyboard != null) { this.roatationStroyboard.Begin(); } } } private void OnLoaded(object sender, RoutedEventArgs e) { HubTileService.Enqueue(this); PulsingTile tile = this; this.Loaded += PulsingTile_Unloaded; this.StartAnimation(); } private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) { PulsingTile tile = sender as PulsingTile; if (tile != null) { tile.StopAnimation(); tile.StartAnimation(); } } private void PulsingTile_Unloaded(object sender, RoutedEventArgs e) { HubTileService.Dequeue(this); this.Unloaded -= PulsingTile_Unloaded; } private void StartAnimation() { this.AnimateContent(); } private void StopAnimation() { if (this.pulseStroyboard != null) { this.pulseStroyboard.Stop(); } if (this.roatationStroyboard != null) { this.roatationStroyboard.Stop(); } } public TimeSpan PulseDuration { get { return (TimeSpan)base.GetValue(PulseDurationProperty); } set { base.SetValue(PulseDurationProperty, value); } } public double PulseScale { get { return (double)((double)base.GetValue(PulseScaleProperty)); } set { base.SetValue(PulseScaleProperty, (double)value); } } public double RadiusX { get { return (double)((double)base.GetValue(RadiusXProperty)); } set { base.SetValue(RadiusXProperty, (double)value); } } public double RadiusY { get { return (double)((double)base.GetValue(RadiusYProperty)); } set { base.SetValue(RadiusYProperty, (double)value); } } public TimeSpan TranslateDuration { get { return (TimeSpan)base.GetValue(TranslateDurationProperty); } set { base.SetValue(TranslateDurationProperty, value); } } }
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:PulsingTile="using:WinRTXamlToolkit.Controls"> <SolidColorBrush x:Key="AccentBrush" Color="#FF1FAEFF" /> <DataTemplate x:Key="ImageTileContentTemplate"> <Grid> <Rectangle Fill="{Binding Background}"/> <Rectangle Fill="White" Opacity="{Binding Opacity}"/> <Image Source="{Binding Image}" Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" HorizontalAlignment="{Binding HorizontalImageAlignment}" VerticalAlignment="{Binding VerticalImageAlignment}" Stretch="UniformToFill"/> </Grid> </DataTemplate> <Style TargetType="ContentControl" x:Key="DefaultHeaderStyle"> <Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="VerticalAlignment" Value="Bottom"/> <Setter Property="Margin" Value="10 5"/> <Setter Property="FontSize" Value="18"/> </Style> <Style TargetType="ContentControl" x:Key="DefaultTitleStyle"> <Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="VerticalAlignment" Value="Top"/> <Setter Property="Margin" Value="5"/> <Setter Property="FontSize" Value="10"/> </Style> <Style TargetType="PulsingTile:PulsingTile" > <Setter Property="Padding" Value="3"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="HeaderStyle" Value="{StaticResource DefaultHeaderStyle}"/> <Setter Property="TitleStyle" Value="{StaticResource DefaultTitleStyle}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="PulsingTile:PulsingTile"> <Grid x:Name="PART_Layout"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="PointerOver"> <Storyboard> <DoubleAnimation Duration="0" To="0.28" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PointerOveRect"/> </Storyboard> </VisualState> <VisualState x:Name="PointerPressed"> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle x:Name="PointerOveRect" Fill="{StaticResource ApplicationForegroundThemeBrush}" Opacity="0" Margin="-2"/> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{TemplateBinding Padding}" x:Name="PART_Border"> <Grid Margin="{TemplateBinding Padding}" > <ContentPresenter x:Name="PART_Content" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" /> <ContentControl Content="{TemplateBinding Title}" Style="{TemplateBinding TitleStyle}"/> <ContentControl Content="{TemplateBinding Header}" Style="{TemplateBinding HeaderStyle}" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" /> </Grid> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style></ResourceDictionary>
以上是主体代码。可以将其复制到项目中编译后可用。
使用方式:
<tools:PulsingTile HorizontalAlignment="Stretch" Width="423423" Height="43423" d:DesignWidth="200" d:DesignHeight="200" Foreground="White" RadiusX="0" RadiusY="0" Title="123123123123" PulseDuration="0:0:5" PulseScale="2" VerticalAlignment="Stretch"> <Image Source="XXXXXXXXXXXXXXXXX"></Image> </tools:PulsingTile>
最终效果:
该磁贴会根据 时间 放大倍数 等参数 定时脉冲缩放