前段时间在银光中国看到
改良仿以然胜甲EaranSE首页动画【感谢原作者】
这篇帖子后,一时兴起,干脆将以然胜甲首页整个仿下来(只是出于兴趣,喜欢的朋友可随意使用,不过出现任何法律后果,与本人概不负责)。
以下是首页部分关键代码
Desktop
public class Desktop : Canvas { private string clickName = string.Empty;//记录单击控件名称 private List<double> Tops = new List<double>();//Top位置坐标 private List<CustomPanel> Panels = new List<CustomPanel>();//Panel集 private int ctlNum = int.MaxValue; private int rowCtlNum = int.MinValue; private bool isLoaded = false; public static readonly DependencyProperty RowsProperty = DependencyProperty.Register("Rows", typeof(int), typeof(Desktop), new PropertyMetadata(1, RowsChanged)); public int Rows { get { return (int)GetValue(RowsProperty); } set { SetValue(RowsProperty, value); } } private static void RowsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { Desktop desktop = sender as Desktop; if (desktop == null) return; int rows = 0; if (e.NewValue != null) int.TryParse(e.NewValue.ToString(), out rows); if (rows > 0) desktop.rowCtlNum = (desktop.ctlNum / rows) + (desktop.ctlNum % rows > 0 ? 1 : 0); } public Desktop() : base() { this.MinWidth = 480; this.MinHeight = 400; this.Loaded += new RoutedEventHandler(Desktop_Loaded); } void Desktop_Loaded(object sender, RoutedEventArgs e) { if (isLoaded) return; for (int i = 0; i < this.Children.Count; i++) { CustomPanel panel = this.Children[i] as CustomPanel; if (panel == null) continue; if (panel.Name == null || panel.Name.Trim() == "") panel.Name = "panel" + i.ToString(); panel.Click += BodyPanel_Click; panel.Margin = new Thickness(5, 3, 3, 3); Panels.Add(panel); } ctlNum = Panels.Count; if (Rows == 0) Rows = 1; rowCtlNum = (ctlNum / Rows) + (ctlNum % Rows > 0 ? 1 : 0); this.SizeChanged += new SizeChangedEventHandler(Desktop_SizeChanged); Desktop_SizeChanged(sender, null); isLoaded = true; } private void Desktop_SizeChanged(object sender, SizeChangedEventArgs e) { Double LWidth = 0;//小对象的宽度 Double MWidth = 0;//大对象的宽度 Double MHeight = 0;//大对象的高度 Double LHeight = 0;//小对象的高度 CalcPanelWidthAndHeight(out LWidth, out LHeight, out MWidth, out MHeight); //判断执行动画 if (string.IsNullOrEmpty(clickName) == true)//初始化动画,也就是第一次点击 { this.Children.Clear(); SetNormalState(MHeight, null); } else { Initialization(MWidth, MHeight, LWidth, LHeight); } } private void SetNormalState(double height, Storyboard sb) { Double MiddleWidth = this.ActualWidth / rowCtlNum - 5;//对象宽度 Double MiddleHeight = height / Rows - rowCtlNum - 5;//对象高度 for (int i = 0; i < ctlNum; i++) { CustomPanel temp = Panels[i]; double left = 0; double top = 0; if (i < rowCtlNum)//控制行Top { top = 2;//第一行顶点 left = MiddleWidth * i + i * 5;//第一行的左边距 } else { top = this.ActualHeight / Rows;//第二行顶点 left = MiddleWidth * (i - rowCtlNum) + (i - rowCtlNum) * 5;//第二行的左边距 } if (sb == null) { temp.Width = MiddleWidth; temp.Height = MiddleHeight; temp.SetValue(Canvas.LeftProperty, left);//与Margin有所不同 temp.SetValue(Canvas.TopProperty, top); this.Children.Add(temp); } else ReducePanel(sb, temp, MiddleWidth, MiddleHeight, top, left); } } private void CalcPanelWidthAndHeight(out double lWidth, out double lHeight, out double mWidth, out double mHeight) { lWidth = 200;//小对象的宽度 mWidth = this.ActualWidth - lWidth - 5;//大对象的宽度 mHeight = this.ActualHeight - 5;//大对象的高度 lHeight = (mHeight - (ctlNum - 1) * 6) / (ctlNum - 1);//小对象的高度 } private void BodyPanel_Click(object sender, RoutedEventArgs e) { CustomPanel panel = sender as CustomPanel; //Canvas ca = panel.Parent as Canvas; Double LWidth = 0;//小对象的宽度 Double MWidth = 0;//大对象的宽度 Double MHeight = 0;//大对象的高度 Double LHeight = 0;//小对象的高度 CalcPanelWidthAndHeight(out LWidth, out LHeight, out MWidth, out MHeight); //判断执行动画 if (string.IsNullOrEmpty(clickName) == true)//初始化动画,也就是第一次点击 { clickName = panel.Name;//保存为上一个点击按钮 Initialization(MWidth, MHeight, LWidth, LHeight); } else { Storyboard sb = new Storyboard(); if (panel.Name == clickName)//还原界面 { //当点击上一个点击的按钮时,还原初始界面 SetNormalState(MHeight, sb); clickName = string.Empty; } else//位置交换 { CustomPanel ctl = this.FindName(clickName) as CustomPanel; MaxPanel(sb, panel, MWidth - 5, MHeight - 10); ctl.Button.IsMax = false; ReducePanel(sb, ctl, LWidth, LHeight, Canvas.GetTop(panel), MWidth); clickName = panel.Name; } sb.Begin(); } } /// <summary> /// 获取每个对象顶点的位置数组 /// </summary> /// <param name="ca"></param> /// <returns></returns> public List<double> topList(Canvas ca) { List<double> ListTmp = new List<double>();//Top位置坐标 //初始化Tops坐标 //Tops.Add((ctlNum - 1)); Double MHeight = this.ActualHeight - 5;//大对象的高度 Double LTop = (MHeight - (ctlNum - 1) * 6) / (ctlNum - 1);//小对象的高度 for (int i = 0; i < ctlNum - 1; i++) { //95:初始化后控件高 3:间距 ListTmp.Add(i * LTop + i * 5 + 5); } return ListTmp; } /// <summary> /// 所有对象归位 /// </summary> /// <param name="MaxWidth">大对象的宽</param> /// <param name="MaxHeight">大对象的高</param> /// <param name="LWidth">小对象的宽</param> /// <param name="LHeight">小对象的高</param> private void Initialization(double MaxWidth, double MaxHeight, Double LWidth, Double LHeight) { Tops = topList(this); Storyboard sb = new Storyboard(); int iTop = 0; for (int i = 0; i < ctlNum; i++) { CustomPanel ctl = Panels[i]; if (ctl.Name == clickName)//判断是否是单击对象 { MaxPanel(sb, ctl, MaxWidth - 5, MaxHeight - 10);//第一次点击时 } else { ctl.Button.IsMax = false; ReducePanel(sb, ctl, LWidth, LHeight, Tops[iTop], MaxWidth);//其它的缩小归位 iTop++; } } sb.Begin(); } /// <summary> /// 放大Panel对象 /// </summary> /// <param name="sb"></param> /// <param name="panel"></param> private void MaxPanel(Storyboard sb, CustomPanel panel, double MaxWidth, double MaxHeight) { sb.Children.Add(CreateDoubleAnimation(panel, "(FrameworkElement.Width)", panel.Width, MaxWidth)); sb.Children.Add(CreateDoubleAnimation(panel, "(FrameworkElement.Height)", panel.Height, MaxHeight)); sb.Children.Add(CreateDoubleAnimation(panel, "(Canvas.Top)", Canvas.GetTop(panel), 5)); sb.Children.Add(CreateDoubleAnimation(panel, "(Canvas.Left)", Canvas.GetLeft(panel), 0)); } /// <summary> /// 缩小Panel对象,也就是小窗口的大小 /// </summary> /// <param name="sb">动画板</param> /// <param name="panel">动画对象</param> /// <param name="width">宽度(缩小目标)</param> /// <param name="height">高度(缩小目标)</param> /// <param name="Top">对象最终顶边</param> /// <param name="Left">对象最终左边</param> private void ReducePanel(Storyboard sb, CustomPanel panel, double width, double height, double Top, double Left) { sb.Children.Add(CreateDoubleAnimation(panel, "(FrameworkElement.Width)", panel.Width, width)); sb.Children.Add(CreateDoubleAnimation(panel, "(FrameworkElement.Height)", panel.Height, height)); sb.Children.Add(CreateDoubleAnimation(panel, "(Canvas.Top)", Canvas.GetTop(panel), Top)); sb.Children.Add(CreateDoubleAnimation(panel, "(Canvas.Left)", Canvas.GetLeft(panel), Left)); } /// <summary> /// 创建一个DoubleAnimation动画对象 /// </summary> /// <param name="element">动画对象</param> /// <param name="property">动画对象属性</param> /// <param name="from">起始值</param> /// <param name="to">结束值</param> /// <returns></returns> public static DoubleAnimation CreateDoubleAnimation(DependencyObject element, string property, double from, double to) { DoubleAnimation da = new DoubleAnimation(); TimeSpan tsBeginTime = new TimeSpan(0, 0, 0, 0, 0);//开始时间 TimeSpan tsDuration = TimeSpan.FromMilliseconds(1000);//播放时间的长度 da.BeginTime = tsBeginTime; da.Duration = new Duration(tsDuration);//播放长度 da.To = to; da.From = from; da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 }; Storyboard.SetTarget(da, element); Storyboard.SetTargetProperty(da, new PropertyPath(property)); return da; } }
CustomPanel
[TemplatePart(Name = StateButton, Type = typeof(PanelButton))] [TemplatePart(Name = ContentContainer, Type = typeof(ContentControl))] [TemplatePart(Name = PanelTitle, Type = typeof(TextBlock))] [TemplatePart(Name = PanelFooter, Type = typeof(TextBlock))] public abstract class CustomPanel : ContentControl { protected internal const string StateButton = "btnMax"; protected internal const string ContentContainer = "contentControl"; protected internal const string PanelTitle = "txtTitle"; protected internal const string PanelFooter = "txtFooter"; protected internal PanelButton btnMax; public PanelButton Button { get { return btnMax; } } protected internal ContentControl contentControl; protected internal TextBlock txtTitle; protected internal TextBlock txtFooter; public event RoutedEventHandler Click; public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(CustomPanel), new PropertyMetadata("", new PropertyChangedCallback(TitleChanged))); public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } private static void TitleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { CustomPanel panel = sender as CustomPanel; if (panel == null) return; if (e.NewValue != null && panel.txtTitle != null) panel.txtTitle.Text = e.NewValue.ToString(); else if (panel.txtTitle != null) panel.txtTitle.Text = ""; } public static readonly DependencyProperty FooterProperty = DependencyProperty.Register("Footer", typeof(string), typeof(CustomPanel), new PropertyMetadata("", new PropertyChangedCallback(FooterChanged))); public string Footer { get { return (string)GetValue(FooterProperty); } set { SetValue(FooterProperty, value); } } private static void FooterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { CustomPanel panel = sender as CustomPanel; if (panel == null) return; if (e.NewValue != null && panel.txtFooter != null) { panel.txtFooter.Text = e.NewValue.ToString(); panel.txtFooter.Visibility = Visibility.Visible; } else if (panel.txtFooter != null) { panel.txtFooter.Text = ""; panel.txtFooter.Visibility = Visibility.Collapsed; } } public new static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(UIElement), typeof(CustomPanel), new PropertyMetadata(null, new PropertyChangedCallback(ContentChanged))); public new UIElement Content { get { return (UIElement)GetValue(ContentProperty); } set { SetValue(ContentProperty, value); } } private static void ContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { CustomPanel panel = sender as CustomPanel; if (panel == null) return; if (e.NewValue != null && panel.contentControl != null) panel.contentControl.Content = e.NewValue; else if (panel.contentControl != null) panel.contentControl.Content = null; } public override void OnApplyTemplate() { base.OnApplyTemplate(); btnMax = base.GetTemplateChild(StateButton) as PanelButton; contentControl = base.GetTemplateChild(ContentContainer) as ContentControl; txtTitle = base.GetTemplateChild(PanelTitle) as TextBlock; txtFooter = base.GetTemplateChild(PanelFooter) as TextBlock; if (btnMax != null) btnMax.Click += new RoutedEventHandler(btnMax_Click); if (contentControl != null) contentControl.Content = Content; if (txtTitle != null) txtTitle.Text = Title; if (txtFooter != null) { txtFooter.Text = Footer; if (Footer.Trim() != "") txtFooter.Visibility = System.Windows.Visibility.Visible; else txtFooter.Visibility = System.Windows.Visibility.Collapsed; } } private void btnMax_Click(object sender, RoutedEventArgs e) { if (Click != null) Click(this, e); } }
PanelButton
public class PanelButton : Button { /// <summary> /// 当前按钮是否选中 /// </summary> public static readonly DependencyProperty IsMaxProperty = DependencyProperty.Register("IsMax", typeof(bool), typeof(PanelButton), new PropertyMetadata(false, new PropertyChangedCallback(IsMaxChanged))); /// <summary> /// 当前按钮是否选中 /// </summary> public bool IsMax { get { return (bool)GetValue(IsMaxProperty); } set { SetValue(IsMaxProperty, value); } } private static void IsMaxChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { PanelButton btn = sender as PanelButton; if (btn == null) return; if (btn.IsMax) { if (btn.IsMouseOver) VisualStateManager.GoToState(btn, "MaxEnter", true); else VisualStateManager.GoToState(btn, "Max", true); } else { if (btn.IsMouseOver) VisualStateManager.GoToState(btn, "UnMaxHover", true); else VisualStateManager.GoToState(btn, "UnMax", true); } } public PanelButton() : base() { this.DefaultStyleKey = typeof(PanelButton); this.Click += new RoutedEventHandler(MenuButton_Click); this.MouseEnter += new MouseEventHandler(PanelButton_MouseEnter); this.MouseLeave += new MouseEventHandler(PanelButton_MouseLeave); } void PanelButton_MouseLeave(object sender, MouseEventArgs e) { if (IsMax) VisualStateManager.GoToState(this, "Max", true); else VisualStateManager.GoToState(this, "UnMax", true); } void PanelButton_MouseEnter(object sender, MouseEventArgs e) { if (IsMax) VisualStateManager.GoToState(this, "MaxEnter", true); else VisualStateManager.GoToState(this, "UnMaxHover", true); } void MenuButton_Click(object sender, RoutedEventArgs e) { IsMax = !IsMax; } }
PanelButton样式,这个放在generic.xaml文件中
<Style TargetType="local:PanelButton"> <Setter Property="IsEnabled" Value="True" /> <Setter Property="IsTabStop" Value="True" /> <Setter Property="Cursor" Value="Hand" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:PanelButton"> <Grid x:Name="Root"> <Rectangle x:Name="NormalState" RadiusX="2" RadiusY="2" Cursor="Hand" Width="11" Height="11" Fill="Transparent" Stroke="{TemplateBinding BorderBrush}" Opacity="1"/> <Rectangle x:Name="HoverState" RadiusX="2" Cursor="Hand" Width="11" Height="11" Stroke="{TemplateBinding BorderBrush}" Opacity="0"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1" Opacity="0.8"> <GradientStop Color="#ffbdc4bb" Offset="0.2"/> <GradientStop Color="#ff6f776c" Offset="0.4"/> <GradientStop Color="#ff363d33" Offset="0.6"/> <GradientStop Color="#ff192016" Offset="0.7"/> <GradientStop Color="#ff4b4e4a" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> <Rectangle.Clip> <RectangleGeometry RadiusX="2" RadiusY="2" Rect="0 0 11 11"/> </Rectangle.Clip> </Rectangle> <Grid x:Name="MaxState" Cursor="Hand" Width="11" Height="11" Background="Transparent" Opacity="0"> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="Transparent"/> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Bottom" HorizontalAlignment="Left" Fill="Transparent"/> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Top" HorizontalAlignment="Right" Fill="Transparent"/> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Bottom" HorizontalAlignment="Right" Fill="Transparent"/> <Grid.Clip> <RectangleGeometry RadiusX="2" RadiusY="2" Rect="0 0 11 11"/> </Grid.Clip> </Grid> <Grid x:Name="MaxHoverState" Cursor="Hand" Opacity="0" Width="11" Height="11" Background="Transparent"> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Top" HorizontalAlignment="Left"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1" Opacity="0.8"> <GradientStop Color="#ffbdc4bb" Offset="0.2"/> <GradientStop Color="#ff6f776c" Offset="0.4"/> <GradientStop Color="#ff363d33" Offset="0.6"/> <GradientStop Color="#ff192016" Offset="0.7"/> <GradientStop Color="#ff4b4e4a" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Bottom" HorizontalAlignment="Left"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1" Opacity="0.8"> <GradientStop Color="#ffbdc4bb" Offset="0.2"/> <GradientStop Color="#ff6f776c" Offset="0.4"/> <GradientStop Color="#ff363d33" Offset="0.6"/> <GradientStop Color="#ff192016" Offset="0.7"/> <GradientStop Color="#ff4b4e4a" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Top" HorizontalAlignment="Right"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1" Opacity="0.8"> <GradientStop Color="#ffbdc4bb" Offset="0.2"/> <GradientStop Color="#ff6f776c" Offset="0.4"/> <GradientStop Color="#ff363d33" Offset="0.6"/> <GradientStop Color="#ff192016" Offset="0.7"/> <GradientStop Color="#ff4b4e4a" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle Width="4.5" Height="4.5" Stroke="{TemplateBinding BorderBrush}" Cursor="Hand" VerticalAlignment="Bottom" HorizontalAlignment="Right"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1" Opacity="0.8"> <GradientStop Color="#ffbdc4bb" Offset="0.2"/> <GradientStop Color="#ff6f776c" Offset="0.4"/> <GradientStop Color="#ff363d33" Offset="0.6"/> <GradientStop Color="#ff192016" Offset="0.7"/> <GradientStop Color="#ff4b4e4a" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Grid.Clip> <RectangleGeometry RadiusX="2" RadiusY="2" Rect="0 0 11 11"/> </Grid.Clip> </Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Unfocused"/> <VisualState x:Name="Focused"/> </VisualStateGroup> <VisualStateGroup x:Name="MaxStates"> <VisualState x:Name="Max"> <Storyboard> <DoubleAnimation Storyboard.TargetName="NormalState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="HoverState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxHoverState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxState" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/> </Storyboard> </VisualState> <VisualState x:Name="UnMax"> <Storyboard> <DoubleAnimation Storyboard.TargetName="NormalState" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/> <DoubleAnimation Storyboard.TargetName="HoverState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxHoverState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> </Storyboard> </VisualState> <VisualState x:Name="MaxEnter"> <Storyboard> <DoubleAnimation Storyboard.TargetName="NormalState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="HoverState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="MaxHoverState" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/> </Storyboard> </VisualState> <VisualState x:Name="UnMaxHover"> <Storyboard> <DoubleAnimation Storyboard.TargetName="NormalState" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="HoverState" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:0.5" To="MouseOver"/> <VisualTransition GeneratedDuration="00:00:0.1" To="Pressed"/> </VisualStateGroup.Transitions> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"/> <VisualState x:Name="Disabled" /> <VisualState x:Name="Normal"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>