说到对象的旋转,或许就会联想到对象角度的概念。对象的旋转实现实际上就是利用对象的角度改变来实现的位置变换,在《Silverlight & Blend动画设计系列二:旋转动画(RotateTransform)》一文中有对对象的不同角度变换的实现介绍,本篇要介绍的自由旋转(Free-form rotation)将借助《Function Silverlight 3 Animation》一书中的示例项目介绍,详细敬请阅读本文。

  要实现自由旋转其实非常简单,需要特别注意的有四点,既旋转对象、旋转中心点、旋转角度及旋转焦点。可以简单理解为当点击对象上的某一点可以对对象实现其以某一中心点为准的不等角度旋转。为了方便控制通常会将旋转焦点设计为相对突出的UI呈现,如下图示:

        

  上图的UI外观设计为一个独立的UserControl,对应的xaml定义如下:


<UserControl x:Class="ImageRotate.RotateItem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="320" Height="240">
    <Canvas x:Name="ItemCanvas" Width="320" Height="240" Canvas.Left="77" Canvas.Top="57" Background="#FFFFFFFF" 
    RenderTransformOrigin="0.5,0.5">
        <Canvas.RenderTransform>
            <TransformGroup>
                <RotateTransform x:Name="RotateItemCanvas" Angle="0"/>
            </TransformGroup>
        </Canvas.RenderTransform>        
        <Image x:Name="Image" Width="300" Height="220" Canvas.Left="10" Canvas.Top="10" Source="" Stretch="Fill"/>
        <Ellipse x:Name="Handle" Width="15" Height="15" Fill="#FFEAFF00" Stroke="#FF000000" Canvas.Left="313" Canvas.Top="233"/>
    </Canvas>
</UserControl>

  分析上面的xaml可以知道,整个界面通过基于坐标的Canvas进行布局,默认设置布局容器的旋转角度为0度,在Canvas里面放置了一个图片作为可旋转的对象外观呈现,一个圆形作为旋转焦点。最终实现旋转功能的就是鼠标在Ellipse对象上的事件应用,通过事件处理函数来改变整个布局容器的旋转角度(Angle)。


private bool IsMouseCaptured;
private Point MousePosition;
private Point LastPosition;
public Point CanvasCenter;
private double LastAngle;
private double CurrentAngle;
private double AngleDelta; public RotateItem()
{
    InitializeComponent();
    //注册Ellipse对象的鼠标事件
    Handle.MouseLeftButtonDown += new MouseButtonEventHandler(Handle_MouseLeftButtonDown);
    Handle.MouseLeftButtonUp += new MouseButtonEventHandler(Handle_MouseLeftButtonUp);
    Handle.MouseMove += new MouseEventHandler(Handle_MouseMove);
} private void Handle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    FrameworkElement Item = sender as FrameworkElement;
    Item.ReleaseMouseCapture();
    IsMouseCaptured = false;
    Item.Cursor = null;
} private void Handle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    FrameworkElement Item = sender as FrameworkElement;
    Item.CaptureMouse();
    Item.Cursor = Cursors.Hand;
    IsMouseCaptured = true;
    LastPosition = e.GetPosition(null);
}

  最关键的就是MouseMove事件了,在MouseMove事件处理函数中,通过计算鼠标点下时的坐标和当前所在的坐标进行弧度转化角度的计算,将得到的角度值设置为Canvas的旋转角度就达到了实现对象的自由旋转功能。

        

  以下为弧度转化为角度的计算公式以及MouseMove事件算法实现:


/// <summary>
/// 弧度转化为角度
/// </summary>
/// <param name="Radians"></param>
/// <returns></returns>
private double RadiansToDegrees(double Radians)
{
    return Radians * 180 / Math.PI;
}

private void Handle_MouseMove(object sender, MouseEventArgs e)
{
    MousePosition = e.GetPosition(null);     if (IsMouseCaptured)
    {
        LastAngle = Math.Atan2(LastPosition.Y - CanvasCenter.Y, LastPosition.X - CanvasCenter.X);
        CurrentAngle = Math.Atan2(MousePosition.Y - CanvasCenter.Y, MousePosition.X - CanvasCenter.X);
        AngleDelta = CurrentAngle - LastAngle;
        RotateItemCanvas.Angle += RadiansToDegrees(AngleDelta);
        LastPosition = MousePosition;
    }
}
可旋转UserControl完整代码

  使用也是非常简单的,动态创建上面所创建的UserControl然后将其添加到主容器控件中就可以了,如下演示代码:


public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();         var Picture1 = new RotateItem();
        Picture1.Image.Source = new BitmapImage(new Uri("Marigold.jpg", UriKind.Relative));
        Picture1.SetValue(Canvas.LeftProperty, 100.00);
        Picture1.SetValue(Canvas.TopProperty, 100.00);
        Picture1.CanvasCenter.X = (double)Picture1.GetValue(Canvas.LeftProperty) + Picture1.Width / 2;
        Picture1.CanvasCenter.Y = (double)Picture1.GetValue(Canvas.TopProperty) + Picture1.Height / 2;
        Picture1.RotateItemCanvas.Angle = -15;
        LayoutRoot.Children.Add(Picture1);
    }
}

        

Silverlight & Blend动画设计系列十二:三角函数(Trigonometry)动画之自由旋转(Free-form rotation)的更多相关文章

  1. Silverlight & Blend动画设计系列十:Silverlight中的坐标系统(Coordinate System)与向量(Vector)运动

    如果我们习惯于数学坐标系,那么对于Silverlight中的坐标系可能会有些不习惯.因为在Silverlight中的坐标系与Flash中的坐标系一样,一切都的颠倒的.在标准的数学坐标系中,X轴表示水平 ...

  2. Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)

    平时我们所看到的雪花(Falling Snow)飘飘的效果实际上也是一个动画,是由许多的动画对象共同完成的一个界面效果.对于不同大小的雪片可以通过缩放变换(ScaleTransform)功能特性确定, ...

  3. Silverlight & Blend动画设计系列十一:沿路径动画(Animation Along a Path)

    Silverlight 提供一个好的动画基础,但缺少一种方便的方法沿任意几何路径对象进行动画处理.在Windows Presentation Foundation中提供了动画处理类DoubleAnim ...

  4. Silverlight & Blend动画设计系列七:模糊效果(BlurEffect)与阴影效果(DropShadowEffect)

    模糊效果(BlurEffect)与阴影效果(DropShadowEffect)是两个非常实用和常用的两个特效,比如在开发相册中,可以对照片的缩略图添加模糊效果,在放大照片的过程中动态改变照片的大小和模 ...

  5. Silverlight & Blend动画设计系列九:动画(Animation)与视图状态管理(Visual State Manager)

    Silverlight中的动画(Animation)与视图状态管理(Visual State Manager) 结合使用是非常常见的,动画用于管理对象在某段事件段内执行的动画动作,视图状态管理则用于控 ...

  6. Web 前端开发精华文章推荐(jQuery、HTML5、CSS3)【系列十二】

    2012年12月12日,[<Web 前端开发人员和设计师必读文章>系列十二]和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HT ...

  7. SQL Server 2008空间数据应用系列十二:Bing Maps中呈现GeoRSS订阅的空间数据

    原文:SQL Server 2008空间数据应用系列十二:Bing Maps中呈现GeoRSS订阅的空间数据 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Se ...

  8. Alamofire源码解读系列(十二)之请求(Request)

    本篇是Alamofire中的请求抽象层的讲解 前言 在Alamofire中,围绕着Request,设计了很多额外的特性,这也恰恰表明,Request是所有请求的基础部分和发起点.这无疑给我们一个Req ...

  9. struts2官方 中文教程 系列十二:控制标签

    介绍 struts2有一些控制语句的标签,本教程中我们将讨论如何使用 if 和iterator 标签.更多的控制标签可以参见 tags reference. 到此我们新建一个struts2 web 项 ...

随机推荐

  1. Visual Studio 2015 Update 2 发布

    2016年3月30日,微软发布了Visual Studio 2015 Update 2 . 更新内容: Visual Studio  Visual Studio Tools for Apache Co ...

  2. django shortcut function

    render() render(request, template_name, context=None, content_type=None, status=None, using=None) 必须 ...

  3. 导出包含图片的excel、word、pdf 笔记

    /** * 导出word * @throws Exception */ @Override public byte[] WordExport( List<VbLibGlobalAnalyList ...

  4. hdu3089 Josephus again|快速约瑟夫环

    题目链接:戳我 貌似是高一昨天的考试题T2?????感觉挺好玩的就搞了搞qwqwq 其实是HDU上面的题啦.... 对于普通的约瑟夫问题,大概是n个人围成一个环,从1开始报数,数到k,那个人出队,最后 ...

  5. JS关闭页面弹窗提醒

    <html> <head><title>JS测试</title> <script type="text/javascript" ...

  6. Python 中当前位置以及目录文件遍历操作

    Python 中当前位置以及目录文件遍历操作 当前位置 print(os.path.dirname(__file__)) 其中 dirname 会选择目录(文件夹),"__file__&qu ...

  7. SpringMVC 的初理解

    项目中用到了jetty,springboot两种构建服务器的方式,jetty是一种嵌入式的方式,部署启动都很灵活,springboot最大的优点就是很多配置文件都自己集成好了,虽然用了这么多好的框架, ...

  8. fetch 请求列表ListView

    //练习二 电影列表(网络请求数据)可参考:http://www.jianshu.com/p/22de6734d858 /** 展示电影列表* 逻辑:* 未获得数据时:显示等待页面* 获得数据时: 显 ...

  9. selectComponent是ok的,小程序组件 component方式,让子页面重绘

    this.selectComponent('#news').init(); 其中news是父级xml文件引用子组件的时给子组件的id. 当父级传给子级的数据有变化时,需要子页面重绘,所以就用上面那行代 ...

  10. Effective C++ 改善55个方法

    美·Scott Meyers 候捷 电子工业 2011 刚才看到个会议时间有点晚,3.25论文都提交了 谷歌去广告的插件, 最后投了这个会议,刚刚好正合适.我说金钱与时间 ACCUSTOMING YO ...