Changing the focused row's children makes RowList report focus at column 0 and back, synchronously Tag: bug-report

Device: Roku Ultra 4800RW, OS 16.0.4 build 834, 1080p (FHD channel)
Component: RowList, rowFocusAnimationStyle: “fixedFocus”
Severity: Medium. Focus doesn’t actually move, but every observer sees it leave the focused item and come back, so the focused item visibly loses and regains its focus state each time a page of items is appended.

Summary

Appending items to the row that has focus (row.appendChildren(items), with focus at rest and no key held) doesn’t move focus. But inside the appendChildren call itself, RowList sets currFocusColumn to 0 and then back to the focused column. Both changes are reported to observers synchronously, before appendChildren returns. The focused item component’s focusPercent follows: it drops to 0 and goes back to 1.

Replacing the focused row with a shorter one (content.replaceChild(newRow, index), where newRow has fewer items than the focused column) reports focus at column 0 within the replaceChild call, rather than at the new row’s last item.

Steps to reproduce

  1. Create a Scene containing a RowList with two rows: row 0 with 4 items and row 1 with 12 items. Set rowFocusAnimationStyle: “fixedFocus”, vertFocusAnimationStyle: “fixedFocus”, itemSize: [1749, 330], rowItemSize: [[398, 330]], rowItemSpacing: [[24, 0]], numRows: 3, and give it focus.
  2. Observe currFocusColumn and rowItemFocused, and in the item component observe focusPercent, printing every change.
  3. Press DOWN to focus row 1, then RIGHT 5 times, and wait for focus to come to rest on [1,5].
  4. Append 8 new ContentNodes to row 1 with appendChildren, printing before and after the call.

Expected

No focus changes are reported. Focus stays on [1,5], and nothing changes for its item component.

Actual

Between the “before” and “after” prints, currFocusColumn is reported as 0 and then as 5. The focused item’s focusPercent is set to 0 and back to 1, so a focus animation driven by it (as in the RowListExample sample) visibly plays out and back in.

Replacing row 1 (focused at [1,5]) with a 3-item row through content.replaceChild reports focus at column 0 within the call, where the new row’s last item, column 2, would be expected.

Notes

  • This happens on every append to the focused row, which is exactly what an app paging a row’s items in as the user nears its end does. currFocusColumn is the field the docs suggest for that pagination.
  • An app that announces focus changes (e.g. for the audio guide) or tracks the focused item also sees a move to column 0 that never happened.
  • Workaround: set a flag around appendChildren/replaceChild on the focused row and ignore reports while it’s set. Afterwards, read rowItemFocused and treat it as a move only if it differs from where focus was. To stop the visible focus animation, the focused item’s component also has to be told to apply the change without animating.