旋转的文字效果
轮换很有趣。 旋转动画时更有趣(正如您将在下一章中看到的那样),但即使使用静态图像也很有趣。
本章和下一章中的几个旋转示例涉及将视觉元素排列在一个圆圈中,所以让我们首先尝试显示一个简单的圆圈。 当然,如果没有Xamarin.Forms中的实际图形系统,我们需要有创造力并用BoxView构建这个圆圈。 如果你使用许多小的BoxView元素并正确排列它们,应该可以创建一个看起来像一个光滑的圆形的东西,如下所示:
每个圆圈由64个BoxView元素组成,每个元素的厚度为4个单位。 这两个值在仅代码的BoxViewCircle程序中定义为常量:
public class BoxViewClockPage : ContentPage
{
const int COUNT = 64;
const double THICKNESS = 4;
public BoxViewClockPage()
{
AbsoluteLayout absoluteLayout = new AbsoluteLayout();
Content = absoluteLayout;
for (int index = 0; index < COUNT; index++)
{
absoluteLayout.Children.Add(new BoxView
{
Color = Color.Accent,
});
}
absoluteLayout.SizeChanged += (sender, args) =>
{
Point center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
double radius = Math.Min(absoluteLayout.Width, absoluteLayout.Height) / 2;
double circumference = 2 * Math.PI * radius;
double length = circumference / COUNT;
for (int index = 0; index < absoluteLayout.Children.Count; index++)
{
BoxView boxView = (BoxView)absoluteLayout.Children[index];
// Position every BoxView at the top.
AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(center.X - length / 2,
center.Y - radius,
length,
THICKNESS));
// Set the AnchorX and AnchorY properties so rotation is
// around the center of the AbsoluteLayout.
boxView.AnchorX = 0.5;
boxView.AnchorY = radius / THICKNESS;
// Set a unique Rotation for each BoxView.
boxView.Rotation = index * 360.0 / COUNT;
}
};
}
}
所有计算都发生在AbsoluteLayout的SizeChanged处理程序中。 AbsoluteLayout的宽度和高度的最小值是圆的半径。知道半径允许计算周长,因此可以计算每个BoxView的长度。
for循环将每个BoxView定位在相同位置:圆圈的中心顶部。然后必须围绕圆心旋转每个BoxView。这需要设置一个AnchorY属性,该属性对应于从BoxView顶部到圆心的距离。该距离是半径值,但必须以BoxView高度为单位,这意味着半径必须除以THICKNESS。
有一种替代方法可以定位和旋转每个不需要设置AnchorX和AnchorY属性的BoxView。这种方法对iOS更好。 for循环首先计算对应于围绕圆周长的每个BoxView中心的x和y值。这些计算需要使用具有半径值的正弦和余弦函数来补偿BoxView的厚度:
for (int index = 0; index < absoluteLayout.Children.Count; index++)
{
BoxView boxView = (BoxView)absoluteLayout.Children[index];
// Find point in center of each positioned BoxView.
double radians = index * 2 * Math.PI / COUNT;
double x = center.X + (radius - THICKNESS / 2) * Math.Sin(radians);
double y = center.Y - (radius - THICKNESS / 2) * Math.Cos(radians);
// Position each BoxView at that point.
AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(x - length / 2,
y - THICKNESS / 2,
length,
THICKNESS));
// Set a unique Rotation for each BoxView.
boxView.Rotation = index * 360.0 / COUNT;
}
x和y值表示每个BoxView中心所需的位置,而AbsoluteLayout.SetLayoutBounds需要每个BoxView左上角的位置,因此当与SetLayoutBounds一起使用时,这些x和y值会根据该差异进行调整。 然后每个BoxView围绕其自己的中心旋转。
现在让我们旋转一些文字。 RotatedText程序完全在XAML中实现:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="RotatedText.RotatedTextPage">
<Grid>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="Text" Value=" ROTATE" />
<Setter Property="FontSize" Value="32" />
<Setter Property="Grid.Column" Value="1" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="AnchorX" Value="0" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Label Rotation="0" />
<Label Rotation="22.5" />
<Label Rotation="45" />
<Label Rotation="67.5" />
<Label Rotation="90" />
<Label Rotation="112.5" />
<Label Rotation="135" />
<Label Rotation="157.5" />
<Label Rotation="180" />
<Label Rotation="202.5" />
<Label Rotation="225" />
<Label Rotation="246.5" />
<Label Rotation="270" />
<Label Rotation="292.5" />
<Label Rotation="315" />
<Label Rotation="337.5" />
</Grid>
</ContentPage>
该程序由Grid中的16个Label元素组成,其中隐式Style设置了六个属性,包括Text和FontSize。 虽然这个Grid似乎只是一个单元格,但它实际上是一个双列Grid,因为Style将每个Label的Grid.Column属性设置为1,这是第二列。 样式在第二列中垂直居中每个标签,并在该列的左侧开始,该列是页面的中心。 但是,文本以几个空格开头,因此它似乎从页面中心的右侧开始。