说到对象的旋转,或许就会联想到对象角度的概念。对象的旋转实现实际上就是利用对象的角度改变来实现的位置变换,在《
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 >
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 );
}
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事件算法实现:
///
/// 弧度转化为角度
///
///
///
private double RadiansToDegrees( double Radians)
{
return Radians * 180 / Math.PI;
}
/// 弧度转化为角度
///
///
///
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;
}
}
{
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完整代码
public
partial
class
RotateItem : UserControl
{
private bool IsMouseCaptured;
private Point MousePosition;
private Point LastPosition;
public Point CanvasCenter;
private double LastAngle;
private double CurrentAngle;
private double AngleDelta;
public RotateItem()
{
InitializeComponent();
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 );
}
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;
}
}
///
/// 弧度转化为角度
///
///
///
private double RadiansToDegrees( double Radians)
{
return Radians * 180 / Math.PI;
}
}
{
private bool IsMouseCaptured;
private Point MousePosition;
private Point LastPosition;
public Point CanvasCenter;
private double LastAngle;
private double CurrentAngle;
private double AngleDelta;
public RotateItem()
{
InitializeComponent();
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 );
}
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;
}
}
///
/// 弧度转化为角度
///
///
///
private double RadiansToDegrees( double Radians)
{
return Radians * 180 / Math.PI;
}
}
使用也是非常简单的,动态创建上面所创建的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);
}
}
{
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动画设计系列文章
《Function Silverlight 3 Animation》----本篇中使用的示例素材选自此书