说到对象的旋转,或许就会联想到对象角度的概念。对象的旋转实现实际上就是利用对象的角度改变来实现的位置变换,在《Silverlight & Blend动画设计系列二:旋转动画(RotateTransform)》一文中有对对象的不同角度变换的实现介绍,本篇要介绍的自由旋转(Free-form rotation)将借助《Function Silverlight 3 Animation》一书中的示例项目介绍,详细敬请阅读本文。
要实现自由旋转其实非常简单,需要特别注意的有四点,既旋转对象、旋转中心点、旋转角度及旋转焦点。可以简单理解为当点击对象上的某一点可以对对象实现其以某一中心点为准的不等角度旋转。为了方便控制通常会将旋转焦点设计为相对突出的UI呈现,如下图示:
上图的UI外观设计为一个独立的UserControl,对应的xaml定义如下:
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
<
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)。
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
private
bool
IsMouseCaptured;
private
PointMousePosition;
private
PointLastPosition;
public
PointCanvasCenter;
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,MouseButtonEventArgse)
{
FrameworkElementItem
=
sender
as
FrameworkElement;
Item.ReleaseMouseCapture();
IsMouseCaptured
=
false
;
Item.Cursor
=
null
;
}
private
void
Handle_MouseLeftButtonDown(
object
sender,MouseButtonEventArgse)
{
FrameworkElementItem
=
sender
as
FrameworkElement;
Item.CaptureMouse();
Item.Cursor
=
Cursors.Hand;
IsMouseCaptured
=
true
;
LastPosition
=
e.GetPosition(
null
);
}
最关键的就是MouseMove事件了,在MouseMove事件处理函数中,通过计算鼠标点下时的坐标和当前所在的坐标进行弧度转化角度的计算,将得到的角度值设置为Canvas的旋转角度就达到了实现对象的自由旋转功能。
以下为弧度转化为角度的计算公式以及MouseMove事件算法实现:
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
///
<summary>
///
弧度转化为角度
///
</summary>
///
<paramname="Radians"></param>
///
<returns></returns>
private
double
RadiansToDegrees(
double
Radians)
{
return
Radians
*
180
/
Math.PI;
}
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
private void
Handle_MouseMove(
object
sender,MouseEventArgse)
{
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然后将其添加到主容器控件中就可以了,如下演示代码:
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
public
partial
class
MainPage:UserControl
{
public
MainPage()
{
InitializeComponent();
varPicture1
=
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动画设计系列文章
《Function Silverlight 3 Animation》----本篇中使用的示例素材选自此书