在 Xamarin 中使用 tvOS 堆积视图
警告
iOS Designer 在 Visual Studio 2019 版本 16.8 和 Visual Studio 2019 for Mac 版本 8.8 中已经弃用,并且已从 Visual Studio 2019 版本 16.9 和 Visual Studio for Mac 版本 8.9 中移除。 要生成 iOS 用户界面,建议直接在运行 Xcode 的 Interface Builder 的 Mac 上操作。 有关详细信息,请参阅用 Xcode 设计用户界面。
堆栈视图控件 (UIStackView
) 利用自动布局和大小类的强大功能来管理子视图堆栈(水平或垂直),从而动态响应 Apple TV 设备的内容更改和屏幕大小。
附加到堆栈视图的所有子视图的布局都基于开发人员定义的属性(如轴、分布、对齐和间距)进行管理:
在 Xamarin.tvOS 应用中使用 UIStackView
时,开发人员可以在 iOS 设计器的 Storyboard 内定义子视图,也可以在 C# 代码中添加和删除子视图。
关于堆积视图控件
UIStackView
设计为非呈现容器视图,因此,它不会像 UIView
的其他子类一样绘制到画布上。 设置属性(如 BackgroundColor
或重写 DrawRect
)不会产生视觉效果。
有几个属性控制堆栈视图如何排列其子视图集合:
- 轴 – 确定堆栈视图是水平还是垂直排列子视图。
- 对齐 - 控制子视图在堆栈视图中的对齐方式。
- 分布 – 控制子视图在堆栈视图中的大小。
- 间距 – 控制堆栈视图中每个子视图之间的最小空间。
- 基线相对 – 如果
true
,每个子视图的垂直间距将从其基线派生。 - 布局边距相对 – 相对于标准布局边距放置子视图。
通常,你将使用堆栈视图来排列少量的子视图。 可以通过将一个或多个堆栈视图嵌套在一个或多个堆栈视图中来创建更复杂的用户界面。
可以通过向子视图添加其他约束(例如控制高度或宽度)来进一步微调 UI 外观。 但是,应注意不要包括堆栈视图本身引入的冲突约束。
自动布局和大小类
当子视图添加到堆栈视图中时,其布局完全由该堆栈视图使用自动布局和大小类来控制排列的视图的位置和大小。
堆栈视图将集合中的第一个和最后一个子视图固定到垂直堆栈视图的上边缘和下边缘或水平堆栈视图的左边缘和右边缘。 如果将属性 true
设置为 LayoutMarginsRelativeArrangement
,则视图会将子视图固定到相关的边距而不是边缘。
堆栈视图在计算所定义的 Axis
(FillEqually Distribution
除外)的子视图大小时使用子视图的 IntrinsicContentSize
属性。 FillEqually Distribution
调整所有子视图的大小,使其大小相同,从而填充沿 Axis
的堆栈视图。
除 Fill Alignment
外,堆栈视图使用子视图的 IntrinsicContentSize
属性来计算与给定 Axis
垂直的视图大小。 对于 Fill Alignment
,所有子视图的大小都大,以便填充垂直于给定 Axis
的堆栈视图。
定位和调整堆栈视图的大小
虽然堆栈视图完全控制任何子视图的布局(基于 Axis
和 Distribution
等属性),但仍需要使用自动布局和大小类将堆栈视图 (UIStackView
) 定位在其父视图中。
通常,这意味着固定堆栈视图的至少两个边缘以展开和收缩,从而定义其位置。 如果没有任何其他约束,堆栈视图将自动调整大小以适应其所有子视图,如下所示:
- 沿其
Axis
的大小将是所有子视图大小的总和以及每个子视图之间定义的任何空间。 - 如果
LayoutMarginsRelativeArrangement
属性为true
,则堆栈视图大小还将包含边距空间。 - 垂直于
Axis
的大小将设置为集合中最大的子视图。
此外,还可以为堆栈视图的高度和宽度指定约束。 在这种情况下,子视图将布局(大小),以填充由堆栈视图指定的空间,由 Distribution
和 Alignment
属性决定。
如果 BaselineRelativeArrangement
属性为 true
,则子视图将基于第一个或最后一个子视图的基线进行布局,而不是使用顶部下方或中心 - Y 位置。 这些计算在堆栈视图的内容上,如下所示:
- 垂直堆栈视图将返回第一个基线的第一个子视图,最后一个子视图返回最后一个子视图。 如果其中任一子视图本身是堆栈视图,则将使用其第一个或最后一个基线。
- 水平堆栈视图将对第一个和最后一个基线使用其最高子视图。 如果最高视图也是堆栈视图,它将使用其最高子视图作为基线。
重要
基线对齐不适用于拉伸或压缩的子视图大小,因为基线将计算到错误的位置。 对于基线对齐,请确保子视图的高度与内部内容视图的高度匹配。
常用堆栈视图使用
有几种布局类型适用于堆栈视图控件。 根据 Apple 的说法,以下是一些更常见的用途:
- 定义沿轴的大小 – 通过将两个边缘固定在堆栈视图的
Axis
和一个相邻边缘来设置位置,堆栈视图将沿轴增长,以适应其子视图定义的空间。 - 定义子视图的位置 – 通过将堆栈视图的相邻边缘固定到父视图的相邻边缘,堆栈视图将在两个维度中增长,以适应其包含子视图。
- 定义堆栈的大小和位置 – 通过将堆栈视图的所有四个边缘固定到父视图,堆栈视图将基于堆栈视图中定义的空间排列子视图。
- 定义轴垂直大小 – 通过将两个边缘固定到堆栈视图的
Axis
和沿轴的一个边缘来设置位置,堆栈视图将垂直于轴,以适应其子视图定义的空间。
堆栈视图和情节提要
在 Xamarin.tvOS 应用中使用堆栈视图的最简单方法是使用 iOS 设计器将它们添加到应用的 UI。
在 Solution Pad 中,双击
Main.storyboard
文件并将其打开进行编辑。设计要添加到堆栈视图的各个元素的布局:
将任何必需的约束添加到元素,以确保它们正确缩放。 将元素添加到堆栈视图后,此步骤非常重要。
创建所需的副本数(在本例中为 4 个):
从工具箱拖动堆栈视图,并将其拖放到视图上:
选择堆栈视图,在属性板的小组件选项卡中,为对齐方式选择填充,为分布选择均等填充,并为 间距输入
25
:将堆栈视图置于所需位置的屏幕上,并添加约束以将其保留在所需位置。
选择各个元素并将其拖动到堆栈视图中:
将调整布局,并且将根据上面设置的属性在堆栈视图中排列元素。
在属性资源管理器的小组件选项卡中分配名称,以在 C# 代码中使用 UI 控件。
保存所做更改。
重要
虽然在创建事件处理程序时,可以在 iOS 设计器中为 UI 元素(如 UIButton
)分配 TouchUpInside
等操作,但永远不会调用它,因为 Apple TV 没有触摸屏,也不支持触摸事件。 创建 tvOS 用户界面元素的操作时,应始终使用默认 Action Type
。
有关使用情节提要的详细信息,请参阅你好,tvOS 快速入门指南。
在本示例中,我们公开了细分控件的出口和操作,以及每个“玩家卡”的出口。 在代码中,我们基于当前段隐藏和显示玩家。 例如:
partial void PlayerCountChanged (Foundation.NSObject sender) {
// Take Action based on the segment
switch(PlayerCount.SelectedSegment) {
case 0:
Player1.Hidden = false;
Player2.Hidden = true;
Player3.Hidden = true;
Player4.Hidden = true;
break;
case 1:
Player1.Hidden = false;
Player2.Hidden = false;
Player3.Hidden = true;
Player4.Hidden = true;
break;
case 2:
Player1.Hidden = false;
Player2.Hidden = false;
Player3.Hidden = false;
Player4.Hidden = true;
break;
case 3:
Player1.Hidden = false;
Player2.Hidden = false;
Player3.Hidden = false;
Player4.Hidden = false;
break;
}
}
运行应用时,这四个元素将同样分布在堆栈视图中:
如果玩家数量减少,则隐藏未使用的视图,并且堆栈视图调整布局以适应以下情况:
从代码填充堆栈视图
除了在 iOS 设计器中完全定义堆栈视图的内容和布局外,还可以从 C# 代码动态创建和删除它。
使用堆栈视图处理审阅中的“星形”的示例(1 到 5):
public int Rating { get; set;} = 0;
...
partial void IncreaseRating (Foundation.NSObject sender) {
// Maximum of 5 "stars"
if (++Rating > 5 ) {
// Abort
Rating = 5;
return;
}
// Create new rating icon and add it to stack
var icon = new UIImageView (new UIImage("icon.png"));
icon.ContentMode = UIViewContentMode.ScaleAspectFit;
RatingView.AddArrangedSubview(icon);
// Animate stack
UIView.Animate(0.25, ()=>{
// Adjust stack view
RatingView.LayoutIfNeeded();
});
}
partial void DecreaseRating (Foundation.NSObject sender) {
// Minimum of zero "stars"
if (--Rating < 0) {
// Abort
Rating =0;
return;
}
// Get the last subview added
var icon = RatingView.ArrangedSubviews[RatingView.ArrangedSubviews.Length-1];
// Remove from stack and screen
RatingView.RemoveArrangedSubview(icon);
icon.RemoveFromSuperview();
// Animate stack
UIView.Animate(0.25, ()=>{
// Adjust stack view
RatingView.LayoutIfNeeded();
});
}
让我们详细查看一下此代码的几个部分。 首先,我们使用 if
语句来检查是否不超过五颗“星”或小于零。
若要添加新的“星形”,请加载其图像并将其内容模式设置为缩放方面拟合:
var icon = new UIImageView (new UIImage("icon.png"));
icon.ContentMode = UIViewContentMode.ScaleAspectFit;
这会使“星形”图标在添加到堆栈视图时被扭曲。
接下来,我们将新的“星形”图标添加到堆栈视图的子视图集合中:
RatingView.AddArrangedSubview(icon);
你会注意到,我们已将 UIImageView
添加到 UIStackView
的 ArrangedSubviews
属性,而不是添加到 SubView
。 希望堆栈视图控制其布局的任何视图都必须添加到 ArrangedSubviews
属性。
若要从堆栈视图中删除子视图,请先获取要删除的子视图:
var icon = RatingView.ArrangedSubviews[RatingView.ArrangedSubviews.Length-1];
然后,我们需要从 ArrangedSubviews
集合和超级视图中删除它:
// Remove from stack and screen
RatingView.RemoveArrangedSubview(icon);
icon.RemoveFromSuperview();
仅从 ArrangedSubviews
集合中删除子视图会将其从堆栈视图的控件中删除,但不会将其从屏幕中删除。
动态更改内容
每当添加、移除或隐藏子视图时,堆栈视图将自动调整子视图的布局。 如果调整了堆栈视图的任何属性(如其 Axis
),布局也将进行调整。
布局更改可以通过将更改放置在动画块中进行动画处理,例如:
// Animate stack
UIView.Animate(0.25, ()=>{
// Adjust stack view
RatingView.LayoutIfNeeded();
});
可以使用情节提要中的大小类指定堆栈视图的许多属性。 这些属性将自动进行动画处理,以响应大小或方向更改。
总结
本文介绍了在 Xamarin.tvOS 应用中设计和处理堆积视图。