曾经在WP7、WP8下的消息 使用的都是Coding4Fun.Phone.Toolkit里面的ToastPrompt类来实现的。
现在我们来自己做个类似IT之家的这种效果:从右边弹出,经过几秒后会自动消失。
首先明确几个需求:
1.在任何界面都能够弹出此消息
2.可以自定义消息的格式内容以及消息的消失时间
(包括是否含有标题、字体大小、排列...)
3.消息的提示与消失都有动画效果
一、取得当前页面上的某个Panel, 用于在此上面呈现消息:
ContentPresenter、Panel都是继承于 FrameWorkElement的
ContentPresenter: 只能容纳一个元素
继承于Panel 的控件是可以容纳多个子控件的,所以将消息显示在这个上面
Panel popUpParentPanel; //消息在此Panel上弹出 Frame RootVisualFrame; //当前页面的可视根 public Panel PopUpParentPanel { get { if (popUpParentPanel == null) { IEnumerable<ContentPresenter> source = CommonHelper.GetVisualDescendants(this.RootVisualFrame).OfType<ContentPresenter>(); //获取所有ContentPresenter类型的子对象 for (int i = 0; i < source.Count<ContentPresenter>(); i++) { IEnumerable<Panel> enumerable2 = CommonHelper.GetVisualDescendants(source.ElementAt<ContentPresenter>(i)).OfType<Panel>(); //获取所有Panel类型的子对象 if (enumerable2.Count<Panel>() > 0) { this.popUpParentPanel = enumerable2.First<Panel>(); //选出第一个Panel break; } } } return this.popUpParentPanel; } }
二、展示Show方法:
bool bLocked; //默认为false public void Show() { if (bLocked) { return; } InitControl(); //有关消息界面的代码略,详细请看后文给出的Demo
if (PopUpParentPanel != null) { //添加消息至Panel if (PopUpParentPanel is StackPanel) { PopUpParentPanel.Children.Insert(0, toastGrid); } else { PopUpParentPanel.Children.Add(toastGrid); } ShowStoryboard(); //开启动画 bLocked = true; } }
获取子元素相关静态类:
public class CommonHelper { public static IEnumerable<DependencyObject> GetVisualChildren(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return GetVisualChildrenAndSelfIterator(element).Skip<DependencyObject>(1); } public static IEnumerable<DependencyObject> GetVisualDescendants(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return GetVisualDescendantsAndSelfIterator(element).Skip<DependencyObject>(1); //去除元素本身 } private static IEnumerable<DependencyObject> GetVisualDescendantsAndSelfIterator(DependencyObject element) { Queue<DependencyObject> iteratorVariable0 = new Queue<DependencyObject>(); iteratorVariable0.Enqueue(element); while (true) { if (iteratorVariable0.Count <= 0) { yield break; } DependencyObject iteratorVariable1 = iteratorVariable0.Dequeue(); yield return iteratorVariable1; foreach (DependencyObject obj2 in GetVisualChildren(iteratorVariable1)) { iteratorVariable0.Enqueue(obj2); } } } private static IEnumerable<DependencyObject> GetVisualChildrenAndSelfIterator(DependencyObject element) { yield return element; int childrenCount = VisualTreeHelper.GetChildrenCount(element); int childIndex = 0; while (true) { if (childIndex >= childrenCount) { yield break; } yield return VisualTreeHelper.GetChild(element, childIndex); childIndex++; } } }
三、显示消息动画效果以及添加消息显示完成事件:
1 public event EventHandler<object> ToastShowComplated; //消息显示完成事件 2 3 public void ShowStoryboard() 4 { 5 Storyboard sbShow = new Storyboard(); 6 sbShow.Completed += sbShow_Completed; //动画完成后开始计时,时间到后消息消失 7 8 //X轴方,向从消息界面一半处开始 9 DoubleAnimation da = new DoubleAnimation() { From = toastGrid.Width / 2, To = 0, Duration = dua }; 10 da.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut }; 11 Storyboard.SetTarget(da, toastTransform); 12 Storyboard.SetTargetProperty(da, "TranslateTransform.X"); //绑定目标属性和以前有些区别 13 sbShow.Children.Add(da); 14 15 //设置透明度从0变为1 16 DoubleAnimation da1 = new DoubleAnimation() { From = 0, To = 1, Duration = dua }; 17 Storyboard.SetTarget(da1, toastGrid); 18 Storyboard.SetTargetProperty(da1, "FrameworkElement.Opacity"); 19 sbShow.Children.Add(da1); 20 21 sbShow.Begin(); //开始动画 22 } 23 void sbShow_Completed(object sender, object e) 24 { 25 IsShow = true; 26 //计时器开始 27 timer = new Timer(new TimerCallback(Time_Completed), null, this.TotalHiddenSeconds * 1000, 0); 28 if (this.ToastShowComplated != null) 29 { 30 ToastShowComplated(this, e); 31 } 32 } 33 34 async void Time_Completed(object e) 35 { 36 timer.Dispose(); 37 await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 38 { 39 HideStoryboard(); 40 }); 41 }
隐藏消息动画以及添加消息隐藏完成事件一样的。
四、使用该自定义消息:
private void btnToast_Click(object sender, RoutedEventArgs e) { CustomToast toast = new CustomToast() { Message = "这是展示的内容!" }; toast.Show(); }
右边是本篇随笔的Demo: CustomToastSample.rar