Silverlight实现类似Mac Dock特效

来源:互联网 发布:starbound知乎 编辑:程序博客网 时间:2024/06/01 13:42

首先,看一下最终的效果图。我采用的开发环境是Visual Studio 2010。


其实,这里要点,主要有两个,一个是计算鼠标位置到每个图像子元素中心位置的函数,另一个是计算放大倍数,放大倍数是鼠标位置到到每个图像子元素中心位置的距离的,具体如下:

下面是计算标位置到每个图像子元素中心位置的距离二次函数

/// <summary>/// 计算鼠标位置到SilverDockItem元素的中心距离/// </summary>/// <param name="mouseArgs">The <see cref="MouseButtonEventArgs"/> instance containing the event data.</param>/// <param name="target">The target.</param>/// <returns></returns>private double CalculateDistance(MouseEventArgs mouseArgs, SilverDockItem target){double mouseX = mouseArgs.GetPosition(target).X - (target.ActualWidth / 2);double mouseY = mouseArgs.GetPosition(target).Y - (target.ActualHeight / 2);double distance = Math.Sqrt(mouseX * mouseX + mouseY * mouseY);return distance;}


下面是计算放大的倍数

/// <summary>/// 计算SilverDockItem元素的放大倍数/// </summary>/// <param name="maxZoom">放大倍数上限,即最大的放大倍数</param>/// <param name="maxDistance">感知长度,超过这个距离后放大倍数保持在1</param>/// <param name="distanceToItem">鼠标到目标Item中心的距离</param>/// <returns></returns>private double Zoom(double maxZoom, double maxDistance, double distanceToItem){//计算放大的倍数,这里放大倍数和鼠标到SilverDockItem元素的中心距离为二次函数关系double zoom = (maxZoom * (distanceToItem - maxDistance) * (distanceToItem - maxDistance)) / (maxDistance * maxDistance + 1);//如果计算放大倍数小于1,返回1,即不进行放大也不缩小//也就是说鼠标到子元素中心距离大于一定值时就不进行缩放了if (zoom < 1){return 1;}else{return zoom;}}

具体开发过程如下:

1. 新建图像子元素SilverDockItem,代码如下:

<UserControl x:Class="SilverControl.SilverDockItem"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d" Height="60" Width="60" SizeChanged="UserControl_SizeChanged">        <Grid x:Name="LayoutRoot">        <Rectangle d:DesignHeight="60" d:DesignWidth="60"  MouseMove="Rectangle_MouseMove" MouseLeave="Rectangle_MouseLeave">            <Rectangle.Fill>                <ImageBrush x:Name="ContentImage" Stretch="Fill" />            </Rectangle.Fill>        </Rectangle>    </Grid></UserControl>

using System;using System.Windows;using System.Windows.Controls;using System.Windows.Input;using System.Windows.Media.Imaging;namespace SilverControl{    public partial class SilverDockItem : UserControl    {        public static readonly double ORIGNSIZE = 60;                //宿主容器,即容纳SilverDock元素的父控件        internal SilverDock Dock { get; set; }        public SilverDockItem(String uri)        {            InitializeComponent();            //设置图像的ImageSource依赖属性,即要显示的图像元素            //下面两句是同样的效果            //ContentImage.SetValue(ImageBrush.ImageSourceProperty, new BitmapImage(new Uri(uri, UriKind.Relative)));            ContentImage.ImageSource = new BitmapImage(new Uri(uri, UriKind.Relative));        }        /// <summary>        /// 计算SilverDockItem元素的放大倍数        /// </summary>        /// <param name="maxZoom">放大倍数上限,即最大的放大倍数</param>        /// <param name="maxDistance">感知长度,超过这个距离后放大倍数保持在1</param>        /// <param name="distanceToItem">鼠标到目标Item中心的距离</param>        /// <returns></returns>        private double Zoom(double maxZoom, double maxDistance, double distanceToItem)        {            //计算放大的倍数,这里放大倍数和鼠标到SilverDockItem元素的中心距离为二次函数关系            double zoom = (maxZoom * (distanceToItem - maxDistance) * (distanceToItem - maxDistance)) / (maxDistance * maxDistance + 1);            //如果计算放大倍数小于1,返回1,即不进行放大也不缩小            //也就是说鼠标到子元素中心距离大于一定值时就不进行缩放了            if (zoom < 1)            {                return 1;            }            else            {                return zoom;            }        }        /// <summary>        /// 计算鼠标位置到SilverDockItem元素的中心距离        /// </summary>        /// <param name="mouseArgs">The <see cref="MouseButtonEventArgs"/> instance containing the event data.</param>        /// <param name="target">The target.</param>        /// <returns></returns>        private double CalculateDistance(MouseEventArgs mouseArgs, SilverDockItem target)        {            double mouseX = mouseArgs.GetPosition(target).X - (target.ActualWidth / 2);            double mouseY = mouseArgs.GetPosition(target).Y - (target.ActualHeight / 2);            double distance = Math.Sqrt(mouseX * mouseX + mouseY * mouseY);            return distance;        }        /// <summary>        /// Handles the MouseMove event of the Rectangle control.        /// </summary>        /// <param name="sender">The source of the event.</param>        /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>        private void Rectangle_MouseMove(object sender, MouseEventArgs e)        {            foreach (var item in Dock.items)            {                double distance = CalculateDistance(e, item);                double zoom = Zoom(Dock.MaxZoom, Dock.MaxDistance, distance);                item.Width = zoom * Dock.Size;                item.Height = zoom * Dock.Size;            }        }        /// <summary>        /// Handles the MouseLeave event of the Rectangle control.        /// </summary>        /// <param name="sender">The source of the event.</param>        /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>        private void Rectangle_MouseLeave(object sender, MouseEventArgs e)        {            foreach (var item in Dock.items)            {                item.Width = ORIGNSIZE;                item.Height = ORIGNSIZE;            }        }        /// <summary>        /// Handles the SizeChanged event of the UserControl control.        /// 当每个SilverDockItem元素的大小改变时,动态修改其承载元素StackPanel的长度,可以可以确保StackPanel始终居中显示        /// </summary>        /// <param name="sender">The source of the event.</param>        /// <param name="e">The <see cref="SizeChangedEventArgs"/> instance containing the event data.</param>        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)        {            double totalWidth = 0;            foreach (var item in Dock.items)            {                totalWidth += item.Width;            }            Dock.ContentPanel.Width = totalWidth;        }    }}

2.新建承载的StackPanel,代码如下:

<UserControl x:Class="SilverControl.SilverDock"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d" Height="100" Width="900" BorderBrush="Black" BorderThickness="1">        <Grid x:Name="LayoutRoot">    <Rectangle Fill="#55000000" Stroke="Black" RadiusX="9" RadiusY="9">    <Rectangle.Effect>    <DropShadowEffect/>    </Rectangle.Effect>    </Rectangle>        <StackPanel x:Name="ContentPanel" Orientation="Horizontal" />    </Grid></UserControl>


using System.Collections.Generic;using System.Windows.Controls;namespace SilverControl{    public partial class SilverDock : UserControl    {        internal List<SilverDockItem> items = new List<SilverDockItem>();        public double Size { get; set; } //SilverDockItem子元素的尺寸,这里SilverDockItem长宽相等        public double MaxDistance { get; set; } //感知长度,超过这个距离后放大倍数保持在1        public double MaxZoom { get; set; } //放大倍数上限,即最大的放大倍数        public SilverDock()        {            InitializeComponent();        }        /// <summary>        /// 给SilverDock工具条动态添加子元素item        /// </summary>        /// <param name="item">SilverDockItem子元素</param>        public void AddItem(SilverDockItem item)        {            item.Dock = this;            item.Height = Size;            item.Width = Size;            items.Add(item);            ContentPanel.Children.Add(item);        }        /// <summary>        /// 从SilverDock工具条中移除SilverDockItem子元素        /// </summary>        /// <param name="item">SilverDockItem子元素</param>        public void RemoveItem(SilverDockItem item)        {            items.Remove(item);            ContentPanel.Children.Remove(item);        }    }}

3.主页面MainPage,代码如下:

<UserControl x:Class="SilverControl.MainPage"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d"    d:DesignHeight="300" d:DesignWidth="400">    <Grid x:Name="LayoutRoot" Background="White">    </Grid></UserControl>

using System.Windows.Controls;namespace SilverControl{    public partial class MainPage : UserControl    {        public MainPage()        {            InitializeComponent();            SilverDock silverDock = new SilverDock();            silverDock.MaxZoom = 1.5;            silverDock.MaxDistance = 600;            silverDock.Size = 60;            silverDock.Size = 60;            LayoutRoot.Children.Add(silverDock);            for (int i = 0; i <= 13; i++ )            {                SilverDockItem item = new SilverDockItem("images/" + i + ".png");                silverDock.AddItem(item);            }        }    }}

有需要源码的同学可以从我的网盘下载。源码下载地址如下:http://yunpan.cn/QI7KHpACMfiXa



0 0
原创粉丝点击