在 Xamarin 中使用 tvOS 导航和焦点

本文介绍了焦点的概念及其用于演示和处理 Xamarin.tvOS 应用中的导航的方式。

本文介绍焦点的概念,说明如何在 Xamarin.tvOS 应用的用户界面中使用它来处理导航。 我们将研究内置 tvOS 导航控件如何使用焦点、突出显示和选择来提供 Xamarin.tvOS 应用的用户界面导航。

tvOS 应用用户界面导航

接下来,我们将探讨焦点如何与视差分层图像一起使用,为最终用户提供当前导航状态的视觉线索。

最后,我们将了解如何使用焦点焦点更新焦点参考线集合中的焦点在 Xamarin.tvOS 应用中启用图像视图的视差

Xamarin.tvOS 应用程序的用户不会像 iOS 用户那样直接在设备屏幕上点击图像与界面进行交互,而是通过 Siri Remote 在房间的另一端进行间接交互。 设计应用的用户界面时,需要记住这一点,以便它自然流动,但仍使用户沉浸于 Apple TV 体验中。

成功的 tvOS 应用以流畅地支持应用的目的和它呈现的数据结构的方式实现导航,而无需引起对导航本身的注意。 设计导航,使其感觉自然而熟悉,而无需主宰用户界面或从内容和应用用户体验中吸引焦点。

tvOS 设置应用

使用 Apple TV 时,用户通常会浏览一组堆积的屏幕,每个屏幕都呈现一组给定的内容。 反过来,每个新屏幕都可能导致使用标准 UI 控件(如按钮制表栏、表、集合视图拆分视图)导致内容分成一个或多个子屏幕。

使用每个新数据屏幕时,用户会更深入地导航到此屏幕堆栈。 通过使用 Siri Remote 上的菜单按钮,他们可以在堆栈中向后导航,以返回到上一个屏幕或主菜单。

Apple 建议在设计 tvOS 应用的导航时记住以下几点:

  • 导航布局,以便快速轻松地查找内容 - 用户希望以最少数量的点击、单击和轻扫访问应用中的内容。 简化导航并将内容组织到最少数量的屏幕。
  • 使用触摸创建 Fluid Interface - 确保用户可以使用最少数量的手势在可聚焦项之间移动。
  • 设计与焦点在脑海中 - 由于用户正在与会议室中的内容交互,因此他们需要在使用 Siri Remote 与内容交互之前将焦点移动到用户界面项。 如果用户需要太多手势才能达到自己的目标,用户会对你的应用感到沮丧。
  • 通过菜单按钮提供向后导航 - 若要创建一种简单而熟悉的体验,允许用户使用 Siri Remote 的菜单按钮向后导航。 按菜单按钮应始终返回到上一个屏幕或返回到应用的主菜单。 在应用的顶层,按菜单按钮应返回到 Apple TV 主屏幕。
  • 通常避免显示后退按钮 - 因为按 Siri Remote 上的菜单按钮会向后导航浏览屏幕堆栈,因此避免显示重复此行为的额外控件。 此规则的例外情况是购买具有破坏性操作的屏幕或屏幕(例如删除内容),其中还应显示“取消”按钮。
  • 在单个屏幕上显示大型集合,而不是许多 - Siri Remote 旨在快速轻松地使用手势浏览大量内容。 如果你的应用适用于大量可聚焦项,请考虑将它们保留在单个屏幕上,而不是将它们分解成许多屏幕,这需要用户部分的更多导航。
  • 使用标准控件进行导航 - 同样,若要创建一种简单且熟悉的用户体验,请尽可能使用内置 UIKit 控件(如页面控件、制表条、分段控件、表视图、集合视图和拆分视图)进行应用导航。 由于用户已经熟悉这些元素,因此他们可以直观地导航应用。
  • 偏向水平内容导航 - 由于 Apple TV 的性质,在 Siri Remote 上向右轻扫比上下更自然。 在为应用设计内容布局时,请考虑此选项。

焦点和选择

在 Apple TV 上,当图像、按钮或其他 UI 元素作为当前导航的目标时,它被视为处于焦点

焦点和选择示例

与 iOS 设备不同,如果用户直接与设备上的触摸屏上的元素交互,则用户使用 Siri Remote 从房间内与 tvOS 元素进行交互。 为了呈现和处理此用户交互,Apple TV 使用基于焦点的模型。

使用 Siri Remote上的手势和按钮按下,用户将焦点从一个 UI 元素移动到另一个 UI 元素。 焦点转移到所需元素后,用户单击以选择内容或激活该元素表示的操作。

随着焦点的变化,微妙的动画和效果(如图像上的视差效果)用于清楚地标识当前具有焦点的用户界面项。

Apple 提供以下使用焦点和选择的建议:

  • 使用内置 UI 控件实现动作效果 - 通过使用用户界面中的 UIKit 和焦点 API,焦点模型将自动将默认运动和视觉效果应用于 UI 元素。 这让 Apple TV 平台的用户感觉你的应用是原生的、熟悉的,并能在可聚焦项之间流畅、直观地移动。
  • 在预期方向移动焦点 - 在 Apple TV 上,几乎每个元素都使用间接操作。 例如,用户使用 Siri Remote 移动焦点,并且系统会自动滚动界面,使当前聚焦的项目保持可见。 如果你的应用实现了这种类型的交互,请确保焦点在用户手势的方向移动。 因此,如果用户向右轻扫 Siri Remote 焦点应向右移动(这可能导致屏幕向左滚动)。 此规则的一个例外是使用直接操作的全屏项(其中向上轻扫将元素向上移动)。
  • 确保重点项明显 - 由于用户从远处与 UI 元素交互,因此当前重点项突出至关重要。这通常由内置 UIKit 元素自动处理。 对于自定义控件,请使用项目大小或阴影等功能来显示焦点。
  • 使用视差使重点项目响应 - Siri Remote 上的小型圆形手势导致焦点项的温和实时移动。 此视差效果内置于UIKit分层图像中,为用户提供与焦点项的连接感。
  • 创建适当大小的可聚焦项 - 具有足够间距的大型项更易于选择和导航。
  • 设计 UI 元素,使其在聚焦或非聚焦状态下都美观大方 - 通常情况下,Apple TV 通过增大聚焦项的尺寸来体现聚焦项。 确保应用的 UI 元素在任何演示文稿大小上看起来都很棒,如果需要,请为较大的元素提供资产。
  • 流畅地表现焦点变化 - 使用动画在项目的 聚焦未聚焦状态之间平滑淡化,使过渡不会显得生硬。
  • 不显示光标 - 用户希望使用焦点导航应用的 UI,而不是通过在屏幕上移动光标来导航。 用户界面应始终使用焦点模型来呈现一致的用户体验。

使用焦点

有时你可能想要创建自定义控件,该控件可以成为可聚焦项。 如果是,替代 CanBecomeFocused 属性并返回 true,否则返回 false。 例如:

public class myView : UIView
{
    public override bool CanBecomeFocused {
        get {return true;}
    }
}

随时可以使用 UIKit 控件的 Focused 属性来查看它是否为当前项。 如果 true,UI 项当前具有焦点,否则不具有焦点。 例如:

// Is my view in focus?
if (myView.Focused) {
    // Do something
    ...
}

虽然不能通过代码直接将焦点移动到另一个 UI 元素,但可以通过将屏幕 PreferredFocusedView 属性设置为 true 来指定哪个 UI 元素首先获得焦点。 例如:

// Make the play button the starting focus item
playButton.PreferredFocusedView = true;

使用焦点更新

当用户使焦点从一个 UI 元素转移到另一个 UI 元素(例如,响应 Siri Remote 上的手势)时,焦点更新事件将发送到失去焦点的项目和获得焦点的项目。

对于从 UIViewUIViewController 继承的自定义元素,可以替代多个方法来处理焦点更新事件:

  • DidUpdateFocus - 每当视图获得或失去焦点时,都将调用此方法。
  • ShouldUpdateFocus - 使用此方法定义允许焦点移动的位置。

若要请求焦点引擎将焦点移回到 PreferredFocusedView UI 元素,请调用视图控制器的 SetNeedsUpdateFocus 方法。

重要

调用 SetNeedsUpdateFocus 仅当要对其调用的视图控制器包含当前具有焦点的视图时才会生效。

使用焦点参考线

内置于 tvOS 中的焦点引擎非常适合处理位于水平网格和垂直网格上的项之间的移动。 通常,只需将 UI 元素添加到界面设计中,焦点引擎会自动处理这些元素之间的移动,而无需开发人员干预。

但是,有时,由于 UI 设计的必要条件,UI 元素不位于水平网格和垂直网格上,并且可能无法访问,因为它们彼此对角。 发生这种情况是因为焦点引擎旨在仅处理 UI 项之间的简单向上、向下、向左和向右移动。

以下方的 UI 布局为例:

使用焦点参考线示例

由于“更多信息”按钮与“购买”按钮不在一个水平和垂直网格上,因此用户无法访问。 但是,可以使用焦点参考线轻松更正此问题,以便向焦点引擎提供移动提示。

焦点参考线 (UIFocusGuide) 将视图的非可见区域公开为焦点引擎,从而允许将焦点重定向到另一个视图。

因此,若要解决上述示例,可以将以下代码添加到视图控制器,以便在“更多信息”和“购买”按钮之间创建焦点参考线:

public UIFocusGuide FocusGuide = new UIFocusGuide ();
...

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Add Focus Guide to layout
    View.AddLayoutGuide (FocusGuide);

    // Define Focus Guide that will allow the user to move
    // between the More Info and Buy buttons.
    FocusGuide.LeftAnchor.ConstraintEqualTo (BuyButton.LeftAnchor).Active = true;
    FocusGuide.TopAnchor.ConstraintEqualTo (MoreInfoButton.TopAnchor).Active = true;
    FocusGuide.WidthAnchor.ConstraintEqualTo (BuyButton.WidthAnchor).Active = true;
    FocusGuide.HeightAnchor.ConstraintEqualTo (MoreInfoButton.HeightAnchor).Active = true;
}

首先,使用 AddLayoutGuide 方法创建一个新的 UIFocusGuide 并将其添加到视图的布局参考线集合中。

接下来,焦点参考线的顶部、左侧、宽度和高度定位点相对于“更多信息”和“购买”按钮进行调整,使其位于它们之间。 请参阅:

示例焦点参考线

另请注意,通过将其 Active 属性设置为 true,激活新约束时会激活这些约束:

FocusGuide.LeftAnchor.ConstraintEqualTo (...).Active = true;

建立并添加到视图的新焦点指南后,可以重写视图控制器的 DidUpdateFocus 方法,并添加以下代码以在“更多信息”和“购买”按钮之间移动:

public override void DidUpdateFocus (UIFocusUpdateContext context, UIFocusAnimationCoordinator coordinator)
{
    base.DidUpdateFocus (context, coordinator);

    // Get next focusable item from context
    var nextFocusableItem = context.NextFocusedView;

    // Anything to process?
    if (nextFocusableItem == null) return;

    // Decide the next focusable item based on the current
    // item with focus
    if (nextFocusableItem == MoreInfoButton) {
        // Move from the More Info to Buy button
        FocusGuide.PreferredFocusedView = BuyButton;
    } else if (nextFocusableItem == BuyButton) {
        // Move from the Buy to the More Info button
        FocusGuide.PreferredFocusedView = MoreInfoButton;
    } else {
        // No valid move
        FocusGuide.PreferredFocusedView = null;
    }
}

首先,此代码从传入的 UIFocusUpdateContext (context) 获取 NextFocusedView。 如果此视图 null,则不需要处理并且方法已退出。

接下来,将评估 nextFocusableItem。 如果它匹配“详细信息”或“购买”按钮,焦点将使用焦点参考线的 PreferredFocusedView 属性发送到相反的按钮。 例如:

// Move from the More Info to Buy button
FocusGuide.PreferredFocusedView = BuyButton;

如果两个按钮都不是焦点移位的源,则会清除 PreferredFocusedView 属性:

// No valid move
FocusGuide.PreferredFocusedView = null;

使用集合中的焦点

在确定单个项是否可以在 UICollectionViewUITableView中聚焦时,将分别替代 UICollectionViewDelegateUITableViewDelegate 的方法。 例如:

public class CardHandDelegate : UICollectionViewDelegateFlowLayout
{
    ...
    public override bool CanFocusItem (UICollectionView collectionView, NSIndexPath indexPath)
    {
        if (indexPath == null) {
            return false;
        } else {
            var controller = collectionView as CardHandViewController;
            return !controller.Hand [indexPath.Row].IsFaceDown;
        }
    }
}

如果当前项可以处于焦点状态,则 CanFocusItem 方法返回 true ,否则返回 false

如果希望 UICollectionViewUITableView 在失去焦点并重新获得焦点时将焦点还原到最后一个项目,请将 RemembersLastFocusedIndexPath 属性设置为 true

焦点和视差

如上所述,当用户界面元素是导航事件期间的当前项时,该元素被视为处于焦点位置。 通常,当项目进入焦点时,它的大小会略有增加,并且使用阴影以视觉方式提升。

如果用户在 Siri Remote 上做出缓慢的圆形手势,重点项目将实时响应此移动。 随着摇摆的发生,一个照亮的希恩应用于其图像,使表面似乎闪耀。 在给定数量的非活动状态后,任何失焦的内容都会变暗,焦点项将增大。

这些效果协同工作,在电视屏幕上的内容与从沙发上与 Apple TV 交互的用户之间提供心理连接。

在 Apple TV 上,此视差效果在整个系统中使用,以传达 3D 深度和动态感到焦点项。 tvOS 使用一系列透明的分层图像,通过动态移动和缩放来产生这种效果。

tvOS 应用的图标需要分层图像,并且支持动态 Top Shelf 内容。 虽然不需要,但 Apple 强烈建议在应用 UI 中的任何其他可聚焦项中实现分层图像。

启用视差

UIImageView 控件(或继承自 UIImageView 的任何控件)自动支持视差效果。 默认情况下,此支持处于禁用状态,若要启用它,请使用以下代码:

myImageView.AdjustsImageWhenAncestorFocused = true;

将此属性设置为 true 后,图像视图将在用户选中并聚焦时自动获取视差效果。

总结

本文介绍了 Focus 的概念及其用于在 Xamarin.tvOS 应用的用户界面中处理导航的方式。 它检查内置 tvOS 导航控件如何使用焦点、突出显示和选择来提供导航。 接下来,它探讨了焦点如何与视差和分层图像一起使用,以便为最终用户提供当前导航状态的视觉线索。 最后,它检查了如何使用焦点、焦点更新、集合中的焦点和启用视差。