Skip to content

feat(iOS, Split): Nesting Stack v5 in SplitView - #4602

Open
t0maboro wants to merge 1 commit into
mainfrom
@t0maboro/split-column-stack
Open

feat(iOS, Split): Nesting Stack v5 in SplitView#4602
t0maboro wants to merge 1 commit into
mainfrom
@t0maboro/split-column-stack

Conversation

@t0maboro

@t0maboro t0maboro commented Sep 4, 2026

Copy link
Copy Markdown
Member

Description

POC of hosting Stack v5 directly inside Split columns on iOS. A Stack.Host mounted as the only child of a Split.Column becomes the column itself: its RNSStackNavigationController is installed as the column's view controller, the stack screens become the column's view controllers.
The stack keeps the exact structure it has standalone. Stack.Host still owns and drives all navigation operations. The only thing that differs is that, for SplitView, the SplitHost is placing that controller in the VC hierarchy. The whole communication goes through a generic protocol, so Split knows nothing about Stack.

Consequence worth stating explicitly: in this mode neither the Split.Column view nor the Stack.Host view is part of the UIKit view hierarchy.

This is an initial PR proposing only the attachment mechanism and the resulting hierarchy. Follow-ups are listed below and are deliberately out of scope of this content.

Closes: https://github.com/software-mansion/react-native-screens-labs/issues/694

Changes

  • RNSNavigationControllerProviding: a component view backed by a UINavigationController exposes it, accepts a flag telling it that the parent places the controller and can apply its pending updates on demand.
  • RNSStackHostComponentView: conforms to that protocol. It keeps owning its RNSStackNavigationController, but didMoveToWindow can skip the self-placement while the flag is set.
  • RNSSplitScreenComponentView: mountChildComponentView: detects a child conforming to the protocol, marks the provider as placed by the parent. The column frame for such a column is reported to the ShadowTree via KVO on the provided controller's view frame (the view is loaded at mount so the very first frame set by UISplitViewController is observed). This is marked as temporary, to be unified with RNSSplitNavigationControllerFrameObserver.
  • RNSSplitHostController: flushes the provider to execute the external controller's updates before the split attaches it.

Out of scope of the POC (known, expected not to work)

  • safe area integration
  • hit testing
  • column lifecycle events are not emitted for stack-backed columns (no RNSSplitScreenController in the hierarchy), stack emits these events instead.
  • inspector column (iOS 26) with a Stack.Host child is not supported yet.
  • Important: frame reporting is split between RNSSplitNavigationControllerFrameObserver (for plain columns) and the KVO in the column view (stack-backed columns); the further direction is one observer per column owned by the native column controller, with the SplitHost talking to columns only.

Before & after - visual documentation

iOS 18 iOS 26
18.mov
26.mov

Test plan

The scenario will be added after discussing the solution. I'd recommend pasting the minimal example into TestSplitPressables for now.

import React from 'react';
import { scenarioDescription } from './scenario-description';
import { createScenario } from '@apps/tests/shared/helpers';
import { Split } from 'react-native-screens';
import { TestStackSubviewsIOS } from '../../stack-v5';

function TestSplitPressables() {
  return (
    <Split.Host preferredDisplayMode="oneBesideSecondary">
      <Split.Column>
        <TestStackSubviewsIOS />
      </Split.Column>
      <Split.Column>
        <TestStackSubviewsIOS />
      </Split.Column>
      <Split.Column>
        <TestStackSubviewsIOS />
      </Split.Column>
    </Split.Host>
  );
}

export default createScenario(TestSplitPressables, scenarioDescription);

Checklist

  • Included code example that can be used to test this change.
  • For visual changes, included screenshots / GIFs / recordings documenting the change.
  • For API changes, updated relevant public types.
  • Ensured that CI passes

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 1ab3e679-5f9f-46d9-b088-b3d0210e2463

📥 Commits

Reviewing files that changed from the base of the PR and between 1bcf216 and ef0eb1e.

📒 Files selected for processing (6)
  • ios/helpers/container/RNSNavigationControllerProviding.h
  • ios/split/RNSSplitHostController.mm
  • ios/split/RNSSplitScreenComponentView.h
  • ios/split/RNSSplitScreenComponentView.mm
  • ios/stack/host/RNSStackHostComponentView.h
  • ios/stack/host/RNSStackHostComponentView.mm

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The iOS split container now accepts navigation controllers supplied by nested stack hosts. Stack hosts expose a provider protocol, split columns manage provider takeover and frame observation, and split hosts integrate supplied controllers while preserving existing native-column behavior.

Provider-backed Split columns

Layer / File(s) Summary
Provider contract and stack host
ios/helpers/container/RNSNavigationControllerProviding.h, ios/stack/host/RNSStackHostComponentView.*
RNSNavigationControllerProviding exposes the navigation controller, parent-placement state, and pending-update flushing. RNSStackHostComponentView implements the protocol and skips self-placement after parent takeover.
Split column provider takeover
ios/split/RNSSplitScreenComponentView.*
Split columns detect provider children, manage takeover and release, observe provided view frames, update shadow state, and request host updates.
Split host navigation controller integration
ios/split/RNSSplitHostController.mm
The split host selects supplied navigation controllers for provider-backed columns and skips those columns during native frame-origin updates.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to ef0eb

This adds support for rendering Stack hosts directly in Split columns while preserving stack navigation ownership and frame updates. No concrete current-head merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant RNSSplitScreenComponentView
  participant RNSStackHostComponentView
  participant RNSSplitHostController
  participant ProvidedView
  RNSSplitScreenComponentView->>RNSStackHostComponentView: Set parent placement
  RNSSplitScreenComponentView->>ProvidedView: Observe frame
  RNSSplitScreenComponentView->>RNSSplitHostController: Request child controller update
  RNSSplitHostController->>RNSStackHostComponentView: Flush pending updates
  RNSStackHostComponentView-->>RNSSplitHostController: Return navigation controller
  ProvidedView-->>RNSSplitScreenComponentView: Report frame change
  RNSSplitScreenComponentView->>RNSSplitHostController: Update shadow frame
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: hosting Stack v5 inside iOS SplitView columns.
Description check ✅ Passed The description directly explains the proof of concept, implementation changes, supported behavior, limitations, and test plan for nesting Stack v5 in SplitView.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@t0maboro

t0maboro commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

assiging @kkafar for reviewing if this is the right direction

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Nested stacks currently regress header hit-testing and navigation-bar visibility.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Enables iOS Split columns to directly host Stack v5 navigation controllers.

Changes:

  • Adds a generic navigation-controller provider protocol.
  • Integrates Stack hosts as Split column controllers.
  • Adds frame reporting for stack-backed columns.
File summaries
File Description
ios/helpers/container/RNSNavigationControllerProviding.h Defines the provider contract.
ios/split/RNSSplitHostController.mm Installs provided controllers.
ios/split/RNSSplitScreenComponentView.h Exposes nested-controller state.
ios/split/RNSSplitScreenComponentView.mm Handles provider mounting and frames.
ios/stack/host/RNSStackHostComponentView.h Adopts the provider protocol.
ios/stack/host/RNSStackHostComponentView.mm Exposes and delegates Stack controller placement.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ios/stack/host/RNSStackHostComponentView.mm
Comment on lines +168 to +170
// Controller's pending updates must be populated before the SplitView attaches it.
[provider flushPendingUpdates];
return provider.navigationController;
Comment on lines 329 to +335
/**
* @brief Gets the children RNSSplitScreenController instances.
* @brief Gets the children UINavigationControllers instances.
*
* Accesses Split controllers associated with presented columns. It asserts that each view controller is a navigation
* controller and its topViewController is of type RNSSplitScreenController.
*
* @return An array of RNSSplitScreenController corresponding to current split view columns.
* @return An array of UINavigationController corresponding to current split view columns.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants