说到对象的旋转,或许就会联想到对象角度的概念。对象的旋转实现实际上就是利用对象的角度改变来实现的位置变换,在《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. Django Query

    Making Qeries 一旦创建了数据模型,Django就会自动为您提供一个数据库抽象API,允许您创建.检索.更新和删除对象.本文档解释了如何使用这个API. The models 一个clas ...

  2. OCP 12c最新考试原题及答案(071-8)

    8.(5-4) choose the best answer:You need to produce a report where each customer's credit limit has b ...

  3. vector迭代器失效的几种情况

    在泛型编程还是STL的实际运用中,迭代器(iterator)无疑扮演者重要的角色.迭代器是一种类似于指针的对象(如可以内容提领,成员访问等),但他又不仅仅是一种普通的指针.关于迭代器失效,我们可以看下 ...

  4. [AIR] AS3读取本地文件夹中的文件

    import flash.filesystem.File; import flash.net.URLLoader; //var dir:File = File.desktopDirectory; // ...

  5. Extjs在form展示后台单个对象的属性

    目的:写一个按钮事件,点击时弹出一个win窗体,里面镶嵌form表单,并且展示后台单个对象的属性 先来后台: public void find(){ String clientId = request ...

  6. .net core webapi发布

    地址:https://www.cnblogs.com/laozhang-is-phi/p/9565227.html#autoid-5-1-0 地址2:https://www.cnblogs.com/f ...

  7. JAVA数据结构--快速排序

    快排概念 快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),一种排序算法,最早由东尼·霍尔提出.在平均状况下,排序个项目要(大O符号)次比较.在 ...

  8. 高阶篇:4.2.1)DFMEA框架搭建,填写项目与要求

    本章目的:明确DFMEA的数量及目标,搭建框架,填写项目与要求. 1.步骤: 1)明确DFMEA的数量及目标: 2)搭建框架(所有DFMEA的): 3)填写项目与要求: 2.1明确DFMEA的数量及目 ...

  9. 标准结构篇:4)EMC电磁兼容

    本章目的:电磁兼容EMC概念,及预防控制手段. 1.前言:电磁兼容EMC概述 电磁兼容是一门新兴的综合性学科.电磁兼容学科主要研究的是如何使在同一电磁环境下工作的各种电气电子设备和元器件都能正常工作, ...

  10. 51nod 1812 树的双直径 题解【树形DP】【贪心】

    老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...