一些乐趣
正如您现在可能看到的那样,AbsoluteLayout通常用于某些特殊目的,否则就不容易了。 其中一些可能实际上被归类为“有趣”。
DotMatrixClock使用模拟的5×7点阵显示器显示当前时间的数字。 每个点都是一个BoxView,单独调整尺寸并定位在屏幕上,并根据点是打开还是关闭而着色为红色或浅灰色。 可以想象,这个时钟的点可以用嵌套的StackLayout元素或Grid组织,但每个BoxView都需要给出一个大小。 这些视图的绝对数量和规律性表明程序员比布局类更了解如何在屏幕上排列它们,因为StackLayout和Grid需要以更通用的方式执行位置计算。 因此,这是AbsoluteLayout的理想工作。
XAML文件在页面上设置一个小填充,并准备AbsoluteLayout以按代码填充:
点击(此处)折叠或打开
-
<ContentPage xmlns=""
-
xmlns:x=""
-
x:Class="DotMatrixClock.DotMatrixClockPage"
-
Padding="10"
-
SizeChanged="OnPageSizeChanged">
-
<AbsoluteLayout x:Name="absoluteLayout"
-
VerticalOptions="Center" />
-
- </ContentPage>
点击(此处)折叠或打开
-
public partial class DotMatrixClockPage : ContentPage
-
{
-
// Total dots horizontally and vertically.
-
const int horzDots = 41;
-
const int vertDots = 7;
-
// 5 x 7 dot matrix patterns for 0 through 9.
-
static readonly int[,,] numberPatterns = new int[10,7,5]
-
{
-
{
-
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 1, 1}, { 1, 0, 1, 0, 1},
-
{ 1, 1, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 0, 0, 1, 0, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0},
-
{ 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0},
-
{ 0, 0, 1, 0, 0}, { 0, 1, 0, 0, 0}, { 1, 1, 1, 1, 1}
-
},
-
{
-
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 0, 1, 0},
-
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 0, 0, 0, 1, 0}, { 0, 0, 1, 1, 0}, { 0, 1, 0, 1, 0}, { 1, 0, 0, 1, 0},
-
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 0, 1, 0}
-
},
-
{
-
{ 1, 1, 1, 1, 1}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0}, { 0, 0, 0, 0, 1},
-
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 0, 0, 1, 1, 0}, { 0, 1, 0, 0, 0}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0},
-
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0},
-
{ 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}
-
},
-
{
-
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0},
-
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
-
},
-
{
-
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 1},
-
{ 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}
-
},
-
};
-
// Dot matrix pattern for a colon.
-
static readonly int[,] colonPattern = new int[7, 2]
-
{
-
{ 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }
-
};
-
// BoxView colors for on and off.
-
static readonly Color colorOn = Color.Red;
-
static readonly Color colorOff = new Color(0.5, 0.5, 0.5, 0.25);
-
// Box views for 6 digits, 7 rows, 5 columns.
-
BoxView[,,] digitBoxViews = new BoxView[6, 7, 5];
-
...
- }
程序的构造函数(如下所示)创建了总共238个BoxView对象并将它们添加到AbsoluteLayout,但它也为digitBoxViews数组中的数字保存了BoxView对象。 (理论上,稍后可以通过索引AbsoluteLayout的Children集合来引用BoxView对象。但是在该集合中,它们看起来只是一个线性列表。将它们存储在多维数组中可以更容易地识别和引用它们。 )所有定位和尺寸均基于AbsoluteLayout成比例,假设其长宽比为41到7,其中包含41个BoxView宽度和7个BoxView高度。
点击(此处)折叠或打开
-
public partial class DotMatrixClockPage : ContentPage
-
{
-
...
-
public DotMatrixClockPage()
-
{
-
InitializeComponent();
-
// BoxView dot dimensions.
-
double height = 0.85 / vertDots;
-
double width = 0.85 / horzDots;
-
// Create and assemble the BoxViews.
-
double xIncrement = 1.0 / (horzDots - 1);
-
double yIncrement = 1.0 / (vertDots - 1);
-
double x = 0;
-
for (int digit = 0; digit < 6; digit++)
-
{
-
for (int col = 0; col < 5; col++)
-
{
-
double y = 0;
-
for (int row = 0; row < 7; row++)
-
{
-
// Create the digit BoxView and add to layout.
-
BoxView boxView = new BoxView();
-
digitBoxViews[digit, row, col] = boxView;
-
absoluteLayout.Children.Add(boxView,
-
new Rectangle(x, y, width, height),
-
AbsoluteLayoutFlags.All);
-
y += yIncrement;
-
}
-
x += xIncrement;
-
}
-
x += xIncrement;
-
// Colons between the hour, minutes, and seconds.
-
if (digit == 1 || digit == 3)
-
{
-
int colon = digit / 2;
-
for (int col = 0; col < 2; col++)
-
{
-
double y = 0;
-
for (int row = 0; row < 7; row++)
-
{
-
// Create the BoxView and set the color.
-
BoxView boxView = new BoxView
-
{
-
Color = colonPattern[row, col] == 1 ?
-
colorOn : colorOff
-
};
-
absoluteLayout.Children.Add(boxView,
-
new Rectangle(x, y, width, height),
-
AbsoluteLayoutFlags.All);
-
y += yIncrement;
-
}
-
x += xIncrement;
-
}
-
x += xIncrement;
-
}
-
}
-
// Set the timer and initialize with a manual call.
-
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimer);
-
OnTimer();
-
}
-
...
- }
点击(此处)折叠或打开
-
double height = 0.85 / vertDots;
- double width = 0.85 / horzDots;
点击(此处)折叠或打开
-
double xIncrement = 1.0 / (horzDots - 1);
- double yIncrement = 1.0 / (vertDots - 1);
时间数字的BoxView对象在构造函数中根本没有着色,但是两个冒号的BoxView对象基于colonPattern数组被赋予Color属性。 DotMatrixClockPage构造函数以一秒钟的计时器结束。
页面的SizeChanged处理程序是从XAML文件设置的。 AbsoluteLayout会自动水平拉伸以填充页面的宽度(减去填充),因此HeightRequest实际上只设置了宽高比:
点击(此处)折叠或打开
-
public partial class DotMatrixClockPage : ContentPage
-
{
-
...
-
void OnPageSizeChanged(object sender, EventArgs args)
-
{
-
// No chance a display will have an aspect ratio > 41:7
-
absoluteLayout.HeightRequest = vertDots * Width / horzDots;
-
}
-
...
- }
点击(此处)折叠或打开
-
public partial class DotMatrixClockPage : ContentPage
-
{
-
...
-
-
bool OnTimer()
-
{
-
DateTime dateTime = DateTime.Now;
-
// Convert 24-hour clock to 12-hour clock.
-
int hour = (dateTime.Hour + 11) % 12 + 1;
-
// Set the dot colors for each digit separately.
-
SetDotMatrix(0, hour / 10);
-
SetDotMatrix(1, hour % 10);
-
SetDotMatrix(2, dateTime.Minute / 10);
-
SetDotMatrix(3, dateTime.Minute % 10);
-
SetDotMatrix(4, dateTime.Second / 10);
-
SetDotMatrix(5, dateTime.Second % 10);
-
return true;
-
}
-
void SetDotMatrix(int index, int digit)
-
{
-
for (int row = 0; row < 7; row++)
-
for (int col = 0; col < 5; col++)
-
{
-
bool isOn = numberPatterns[digit, row, col] == 1;
-
Color color = isOn ? colorOn : colorOff;
-
digitBoxViews[index, row, col].Color = color;
-
}
-
}
- }
当然,越大越好,所以你可能想要将手机(或书)侧身转向足够大的东西,从房间的另一端读取:
适用于AbsoluteLayout的另一种特殊类型的应用是动画。 BouncingText程序使用其XAML文件来实例化两个Label元素:
点击(此处)折叠或打开
-
<ContentPage xmlns=""
-
xmlns:x=""
-
x:Class="BouncingText.BouncingTextPage">
-
<AbsoluteLayout>
-
<Label x:Name="label1"
-
Text="BOUNCE"
-
FontSize="Large"
-
AbsoluteLayout.LayoutFlags="PositionProportional" />
-
<Label x:Name="label2"
-
Text="BOUNCE"
-
FontSize="Large"
-
AbsoluteLayout.LayoutFlags="PositionProportional" />
-
-
</AbsoluteLayout>
- </ContentPage>
代码隐藏文件以15毫秒的持续时间启动计时器。 这相当于每秒约60个滴答,这通常是视频显示的刷新率。 15毫秒的计时器持续时间是执行动画的理想选择:
点击(此处)折叠或打开
-
public partial class BouncingTextPage : ContentPage
-
{
-
const double period = 2000; // in milliseconds
-
readonly DateTime startTime = DateTime.Now;
-
public BouncingTextPage()
-
{
-
InitializeComponent();
-
Device.StartTimer(TimeSpan.FromMilliseconds(15), OnTimerTick);
-
}
-
bool OnTimerTick()
-
{
-
TimeSpan elapsed = DateTime.Now - startTime;
-
double t = (elapsed.TotalMilliseconds % period) / period; // 0 to 1
-
t = 2 * (t < 0.5 ? t : 1 - t); // 0 to 1 to 0
-
AbsoluteLayout.SetLayoutBounds(label1,
-
new Rectangle(t, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
-
AbsoluteLayout.SetLayoutBounds(label2,
-
new Rectangle(0.5, 1 - t, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
-
return true;
-
}
- }
Windows 10 Mobile截图确认,两个Label视图每秒都会在中心短暂相遇。
从现在开始,我们的Xamarin.Forms应用程序的页面将变得更加活跃,动画和动态。 在下一章中,您将看到Xamarin.Forms的交互式视图如何在用户和应用程序之间建立通信方式。