UWP - 開發 Xbox App 處理 XY navigation

只要是 Windows 10 的作業系統都可執行 Universal Windows Platform 開發的 Apps,當然包括 Xbox one。
本篇介紹移植 App 到 Xbox 時需要調整的地方。

開發 Xbox 上的 App 有幾個重點:

根據 Designing for Xbox and TV 的説明,做在沙發使用 gamepad 或 remote 去控制 TV,這個行爲被稱爲 10-foot experience

因爲通常沙發跟電視的距離約 10 feet;而 2-foot experience 説明的是 PC。 開發 Xbox 的應用要把握這個距離原則,做到幾個重點:

  • Simple
    解析度與距離的關係,用戶很難處理畫面太多的資訊,應該保持乾净的設計,減少到最簡單的畫面元件,
    可能畫面會接近在 Mobile 的内容而不像 Desktop 這麽多元
  • Coherent
    App 設計應該簡單容易操作,是 focus 清楚,移動的距離,階層,路徑都是一致且最少步驟就能完成想做的事情。
  • Gamepad and remote control
    重要的步驟,決定用戶如何操作 gamepad 或 remote 使用 App 的功能又不會不方便,
    參考 XY focus navigation and interactionMouse mode 調整操作元件的方式。
    開始前建議先使用 keyboard 操作 App 找到那些畫面或是元件的問題,再開始調整 上圖是 gamepad 與 remote 按鈕的差別與介紹,按鈕的使用建議優先支援共用的會比較好,例如:X/Y/A(select)/B(back) buttons 與 menu/views button。
    按下 B(back) button 時,可利用 SystemNavigationManager.BackRequested 直接控制。
    gamepad 的按鈕上也額外支援一些特定的控制項,例如:ScrollViewer 的就可以用 left/right trigger 快速垂直 scroll,可參考 Gamepad and remote control
  • XY focus navigation and interaction
    gamepad 或 remote 只支援移動到擁有 IsTabStop = trueVisibility = visible 的控制項,可參考 Keyboard interactions
    同理如果支援 keyboard 操作的更完整,您的 App 將會變的更方便。
    利用 FocusManager.GetFocusedElement 得知現在那個控制項被 focus,用於瞭解目前 focus 到底跑到哪裏。
    page.GotFocus += (object sender, RoutedEventArgs e) =>
    {
        FrameworkElement focus = FocusManager.GetFocusedElement() as FrameworkElement;
        if (focus != null)
        {
            Debug.WriteLine("got focus: " + focus.Name + " (" +
                focus.GetType().ToString() + ")");
        }
    };
    有些狀況可能造成 XY navigation 移動到非預期的對象:
    • IsTapStop 或是 Visibility 設定錯誤
    • 被 focus 的控制項實際上比看到的還要大,因爲 XY navigation 使用的是 ActualWidth/ActualHeight
    • 不支援重曡的控制項被 focus,一次只能 focus 一個控制項
    UWP 會預設自動計算 focus 要移動的方向與對應的控制項,但是它無法保證真的符合用戶的需求。
    如果 XY navigation 走向的位置不符合預期的話就要覆寫控制項的 XY navigation,强迫給定每個控制項的位置關係,可以參考 Overriding the default navigation
    如果覆寫 XY navigation 不需要重覆指定,例如: Button1.XYFocusLeft = Button2 而在 Button2.XYFocusRight = Button1
    如果覆寫 XY navigation 控制項内的子控制項一樣會承接這個設定。
    如果 XY navigation 是正常的,但是 focus visual 在 focus 時沒有顯示,可以參考下面的排除方式:
    • re-template 控制項,而且拿掉 focus virtual。搭配 UseSystemFocusVisuals="True" 或是手動加入 focus visual 來確認
    • 利用 Focus(FocusState.Pointer) 移動 focus 確定控制項有被 focus。通常會用 Focus(FocusState.Programmatic)。
    Path of least clicks:設計最短的操作距離讓用戶可以完成任務,減少畫面左右滑動的設計,讓用戶上下移動就可以完成。
    CommandBar 與 ContextFlyou:ContextFlyout 可以處理 gamepad 上的 menu 按鈕來完成;
    CommandBar 在 Xbox 上的操作不是這麽容易,建議改用 ContextFlyou 或是其他元件代替,可參考 Problem: UI elements located after long scrolling list/grid
  • Mouse mode
    App.xaml.cs 的建構子加入 disable mouse mode:
    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;
    
        if (IsXbox())
        {
            Application.Current.RequiresPointerMode = ApplicationRequiresPointerMode.WhenRequested;
        }
    }
    
    static string deviceFamily;
    
    public static bool IsXbox()
    {
        if (deviceFamily == null) 
        {
            deviceFamily = Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily;
        }
    
        return deviceFamily  == "Windows.Xbox";
    }
    
    另外,有些 Control 則需要 Mouse mode 來操作,需要另外加入 IsEngagementRequired="true",這樣 Control 才會被進入並開啓 Mouse mode,例如: MapControl。
    <Page>
        <Grid>
            <MapControl IsEngagementRequired="true"
                        RequiresPointer="WhenEngaged"/>
        </Grid>
    </Page>
    
    另外, Page 支援設定 RequiresPointer="WhenFocused" 其他控制項目不可以設定這個屬性,如果是 full screen 的呈現時,例如看 video 時,
    不希望有 mouse mode 出現,可以在該 Page 設定 RequiresPointer="Never"
  • Focus visual
    focus visual 是周圍邊框表示目前控制項被關注,幫用戶簡單的知道目前位置與瀏覽的方向。
    雖然把 focus visual 的控制設定好可以跨所有裝置,但是在 10-foot experience (電視或更大的屏幕)還是有些不同。
    因爲畫面太大用戶很難一次看到全部的範圍,因此在 focus visual 需要更明顯與清楚的顯示,避免用戶做視覺的搜索。
    電視設計不像鍵盤,建議預設就幫用戶關注一個控制項目,讓用戶方便找到瀏覽方向。 整理幾個重點:
    • Initial focus visual placement
      當 App 被啓動或是進去某個 Page,請幫用戶自動 focus 到畫面中你預期開始操作的位置。
      例如:photo app 預設選擇第一張圖片;music app 預設選擇第一首歌曲。
      也可以預設將焦點放在左上角區域,因爲大部分的 App 操作流程都是從左上角開始。
    • Making focus clearly visible
      建議屏幕是始終有一個焦點,用戶就能快速找到關注的地方。但是如果畫面是一個 full screen 的 video / photo / documents 就不一定適合。
    • Customizing the focus visual
      每個控制項目都具有一些焦點視覺相關的屬性可以調整,也可以使用 VisualState 定義不同狀態下要顯示的樣式。
      另外,進階一點使用 Visual layer 的效果做到一些焦點的特效。
    • Light dismiss overlay
      爲了使用戶注意當前用 gamepad 或是 remote control 操作的 UI 元素,UWP 自動添加了一個 Smoke layer 讓彈跳式 UI 在顯示時自動遮住背後的内容,
      讓用戶專注在彈跳出來的内容。 這個不需要額外的處理,
      但要注意在使用 FlyoutBase 的控制項時可以操作 LightDismissOverlayMode 屬性設定是否要顯示 smoke layer。
      可參考 Modal vs light dismiss
  • Focus engagement (非常重要)
    Focus engagement 讓使用 gamepad 或 remote control 更容易操作 App。
    設定 Focus engagement 不會影響 keyboard 或是其他輸入裝置。
    設定 FrameElementIsFocusEngagementEnabled = "True" 時,代表控制項請求 focus engagement。
    用戶使用 gamepad 移動到該控制項時,需要按下 A/Select 按鈕才能與它互動。
    操作完成之後需要按下 B/Back 按鈕才會離開該控制項,繼續瀏覽其他控制項。
  • Focus trapping
    Focus trapping 代表的是當用戶在瀏覽控制項時突然在某個控制項直接陷入到裏面,
    造成用戶原本預期是到下一個控制項但是卻跑到裏面。
    利用下圖的範例來説明: 有 3 個控制項: button1, slider, button2, 當用戶操作預期從 butotn1 到 button2 時會遇到卡在 slider 裏面,
    不管左右移動都是在移動 slider 的光棒。 要解決這樣的問題有很多方式,最簡單從排版方式下手如下圖: 或者搭配 XY focus navigation and interaction 改寫控制項的 XY focus。
    另外可以設定 Slider 的 IsFocusEngagementEnabled = "True",而操作的結果如下圖:
  • Items controls
    其他設定 engagement 的控制項有: ListView, ListBox, GridView, FlipView 如上圖要從 top button 移動到 bottom button,用戶會預期按往下按鈕就會直接到,
    事實上當進去 ListView 時就會自動 focus 到第一個 item,而用戶要一路走到最後一個 item 才能離開 ListView 到 bottom button,
    相反的如果要回去 top button 則是要走到第一個 item 才能出去。
    這樣的操作會讓用戶抓狂,所以需要設定 IsFocusEngagementEnabled = "True",變成如下的操作流程:
    如果是 ScrollViwer 需要考慮用法:
    • 内容有其他控制項,預設進去 ScrollViewr 會自動 focus 到第一個控制項,允許用戶左右移動瀏覽不同的控制項目;
    • 内容為文字瀏覽或是圖片瀏覽時,則需要設定 IsFocusEngagementEnabled = "True",讓用戶方便進入與離開内容;
      更可以設定 IsTapStop = "True",讓操作不需要透過 engage 的方式,而是焦點直接放在 ScrollViewer 直接 scroll 移動。
  • Focus engagement defaults
    有一些控制項因容易操作焦點迷失(例如自動 engage 造成 focus 消失)而預設的 IsFocusEngagementEnabled 是 false,
    但我們還是可以打開它,下面列出幾個常使用的控制項:
    Control Focus engagement default
    CalendarDatePicker On
    FlipView Off
    GridView Off
    ListBox Off
    ListView Off
    ScrollViewer Off
    SemanticZoom Off
    Slider On

還有很多開發與設計上面需要注意的地方,

本篇先寫到這裏下一篇將繼續介紹: UI element sizing, TV-safe area, Color, Custom visual state trigger for Xbox, ... 等。

[補充]

  • 由於 App 在 Xbox 上可用記憶體有限,建議跟 Desktop/Mobile 的專案切開,因爲記憶體的控制會是花最多時間的地方
  • 上架到 Dev Center 時,可以搭配 TargetDeviceFamily 切開讓 Xbox 是另外一個安裝檔
  • UWP App 在封裝時, Version 只能用到前 3 碼 (例如: 1.0.0.{不可用}),最後一碼是不可以用的,
    因爲微軟把它用來顯示特定的設備,例如:Xbox 上安裝 App 之後會發現版本號碼變成了 1.0.0.6

更多詳細的内容,參考 What's new for developers in the latest update of UWP on Xbox One

======

開發 Xbox 的 App 最大難度在於 focus 的控制,因爲 XAML 的組合會造成 focus 的困難或是迷失, 建議 Xbox 跟 Desktop/Mobile 分開 UI 設計比較好。

另外 Xbox 通常搭配電視(或是更大的屏幕)與眼睛距離較遠,内容簡單清楚是必要的。

最後因爲用戶沒有游標時,對於内容過長或是過多時都會讓用戶需要不斷地點擊方向鍵,是非常苦難的。

所以多做一些 Master Detail 的分層,讓畫面乾净與容易操作。 希望對大家有所幫助,謝謝。

References: