• WPF中如何通过Transform类实现FrameworkElement对象的2D转换
  • 发布于 1周前
  • 43 热度
    0 评论
  • 乌龙山
  • 0 粉丝 41 篇博客
  •   
在WPF开发中,经常会需要用到UI控件的2D转换(如:旋转,缩放,移动,倾斜等功能),本文以一些简单的小例子,简述如何通过Transform类实现FrameworkElement对象的2D转换,仅供学习分享使用,如有不足之处,还请指正。

什么是Transform?
转换(Transform)定义如何将控件从一个坐标空间映射或转换到另一个坐标空间。2D转换可以通过Matrix来实现,Matrix是一个3行3列的double值的集合。不过WPF还提供了多个Transform类,以便在不知道基础矩阵结构配置的情况下转换对象。

WPF提供了2D转换(Transform)类,常见的有以下几种:
RotateTransform,按指定的角度(Angle)旋转元素。
ScaleTansform,按指定的坐标方向(ScaleX和ScaleY)缩放元素。
SkewTransform,按指定的角度(AngleX和AngleY)倾斜元素。
TranslateTransform,按指定的X轴和Y轴移动元素。

为了创建更复杂的转换(Transform),WPF还提供了组合转换。如下所示:
TransformGroup,将多个TransformGroup对象组成单个Transform,然后就可以应用到一个UI元素的Transform属性上。
MatrixTransform,创建自定义的转换,使用MatrixTransform时,可以直接操作矩阵。

转换和坐标系
转换对象时,同时还会转换对象所在的坐标空间。默认情况下,除TranslateTransform外,转换基于目标对象的坐标系的左上角(0,0)进行转换。如果想要修改转换基点,可以通过CenterX,CenterY属性进行修改。
以左上角(0,0)进行旋转,如下所示:

以矩形中心进行旋转,如下所示:

转换元素
如果想要将转换应用到控件元素(FrameworkElement),需要创建Transform并应用到FramworkElement类所提供的两个属性之一。控件所对应的两个转换属性,分别如下所示:
LayoutTransform,在布局之前应用转换,布局系统处理转换之后的大小和定位。
RenderTransform,修改元素外观的转换,在布局完成后应用。

将Transform应用到两个属性,都可以达到想要的效果,至于要使用哪个属性,可以根据不同场景进行区分:
在对元素进行缩放,选择,或倾斜,并且需要父级元素来对元素转换后的大小进行调整的,可以使用LayoutTransform属性。
如果使用动画处理后的Transform对象时,可以使用RenderTransform。并且由于RenderTransform属性提供性能优势,所以应尽可能的使用此属性。

旋转RotateTransform
默认情况下,RotateTansform围绕点(0,0)选择,如下所示:
<Border Margin="30" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="1" >
    <StackPanel Orientation="Vertical">
        <Button Content="A Button" Opacity="1" />
        <Button Content="Rotated Button">
            <Button.RenderTransform>
                <RotateTransform Angle="45" />
            </Button.RenderTransform>
        </Button>
        <Button Content="A Button" Opacity="1" />
    </StackPanel>
</Border>
旋转效果,如下所示:

通过RenderTransformOrigin属性,可以设置应用旋转变换的坐标。如下所示:
<Border Margin="30" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="1" >
    <StackPanel Orientation="Vertical">
        <Button Content="A Button" Opacity="1" />
        <Button Content="Rotated Button" RenderTransformOrigin="0.5,0.5">
            <Button.RenderTransform>
                <RotateTransform Angle="45" />
            </Button.RenderTransform>
        </Button>
        <Button Content="A Button" Opacity="1" />
    </StackPanel>
</Border>
修改应用变换坐标后,如下所示:

上述RenderTransformOrigin是相对坐标,范围从(0,0)到(1,1),同样也可以通过RotateTransform的CenterX,CenterY属性进行实现相同的效果。
如果将Transform应用到LayoutTransform,则将导致影响按钮的布局,从而触发布局系统的整个处理过程。如下所示:
<Border Margin="30" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="1">
    <StackPanel Orientation="Vertical">
        <Button Content="A Button" Opacity="1" />
        <Button Content="Rotated Button">
            <Button.LayoutTransform>
                <RotateTransform Angle="45"  />
            </Button.LayoutTransform>
        </Button>
        <Button Content="A Button" Opacity="1" />
    </StackPanel>
</Border>
应用到LayoutTransform的选择效果,如下所示:

缩放ScaleTransform
通过ScaleTransform可以对元素进行缩放,通过使用ScaleX,ScaleY属性进行缩放。这两个属性是相对值,表示缩放的倍数,小于1表示缩小,大于1表示放大,等于1表示原始大小。使用CenterX,CenterY属性指定缩放操作的中心点。
缩放示例如下所示:
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Stroke="Blue" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100">
    <Rectangle.RenderTransform>
        <ScaleTransform CenterX="0" CenterY="0" ScaleX="2" ScaleY="2" />
    </Rectangle.RenderTransform>
</Rectangle>
通常,将 CenterX 和 CenterY 设置为缩放对象的中心:(Width/2、Height/2)。
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Canvas.Left="100" Canvas.Top="100" Stroke="Blue" StrokeThickness="2">
    <Rectangle.RenderTransform>
        <ScaleTransform CenterX="25" CenterY="25" ScaleX="2" ScaleY="2" />
    </Rectangle.RenderTransform>
</Rectangle>
下图显示了两个 ScaleTransform 操作之间的差异。虚线显示的是矩形在缩放之前的大小和位置。

倾斜扭曲SkewTransform
扭曲(也称为修剪)是一种以非均匀方式拉伸坐标空间的转换。SkewTransform 的一种典型用途是在 2D 对象中模拟 3D 深度。
SkewTransform的主要特点如下所示:
使用 CenterX 和 CenterY 属性指定 SkewTransform 的中心点。
使用 AngleX 和 AngleY 属性指定 x 轴和 y 轴的扭曲角度,并沿这些轴扭曲当前坐标系统。

示例:如果 AngleX 为 30,则 y 轴绕原点旋转 30 度,将 x 轴的值从该原点扭曲 30 度。同样地,如果 AngleY 为 30,则将形状的 y 值从原点扭曲 30 度。 
以下示例向 Rectangle 应用自中心点 (0,0) 的 45 度水平扭曲。
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Stroke="Blue" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100">
    <Rectangle.RenderTransform>
        <SkewTransform CenterX="0" CenterY="0" AngleX="45" AngleY="0" />
    </Rectangle.RenderTransform>
</Rectangle>
以下示例向 Rectangle 应用自中心点 (25,25) 的 45 度水平扭曲。
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Canvas.Left="100" Canvas.Top="100" Stroke="Blue" StrokeThickness="2">
    <Rectangle.RenderTransform>
        <SkewTransform CenterX="25" CenterY="25" AngleX="45" AngleY="0" />
    </Rectangle.RenderTransform>
</Rectangle>
以下示例向 Rectangle 应用自中心点 (25,25) 的 45 度垂直扭曲。
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Stroke="Blue" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100">
    <Rectangle.RenderTransform>
        <SkewTransform CenterX="25" CenterY="25" AngleX="0" AngleY="45" />
    </Rectangle.RenderTransform>
</Rectangle>
上述三个示例的效果图如下所示:

移动TranslateTransform
TranslateTransform主要用于元素的平移(移动),如将TranslateTransform应用于元素的RenderTransform属性,可以在StackPanel或DockPanel内移动元素。可以使用TranslateTransform的X属性和Y属性指定按哪个轴进行移动(单位是像素)。
以下示例使用 TranslateTransform 将元素向右移动 50 个像素,向下移动 50 个像素。
<Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Stroke="Blue" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100">
    <Rectangle.RenderTransform>
        <TranslateTransform X="50" Y="50" />
    </Rectangle.RenderTransform>
</Rectangle>
组合转换TransformGroup
通过TransformGroup可以将多个Transform对象合并成一个复合的Transform,并应用到元素的属性。
下面的示例使用 TransformGroup 将 ScaleTransform 和 RotateTransform 应用到 Button。
<Button RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" Content="Click">
    <Button.RenderTransform>
        <TransformGroup>
            <ScaleTransform ScaleY="3" />
            <RotateTransform Angle="45" />
        </TransformGroup>
    </Button.RenderTransform>
</Button>

用户评论