Skip to content

Fix PinnedHeaderSliver semantics focus capture#179023

Merged
auto-submit[bot] merged 5 commits intoflutter:masterfrom
sncf-connect-tech:pinned_header_sliver_semantics_focus
Mar 13, 2026
Merged

Fix PinnedHeaderSliver semantics focus capture#179023
auto-submit[bot] merged 5 commits intoflutter:masterfrom
sncf-connect-tech:pinned_header_sliver_semantics_focus

Conversation

@manu-sncf
Copy link
Contributor

@manu-sncf manu-sncf commented Nov 24, 2025

Fix #179022

Pre-launch Checklist

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: scrolling Viewports, list views, slivers, etc. labels Nov 24, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request fixes a semantics issue for PinnedHeaderSliver by correctly tagging it to be excluded from scrolling semantics. The change is correct and follows the intended use of RenderViewport.excludeFromScrolling. I've added one comment regarding documentation to improve code clarity based on the repository's style guide.

@justinmc
Copy link
Contributor

@manu-sncf Would you be able to add a test for this?

@manu-sncf manu-sncf force-pushed the pinned_header_sliver_semantics_focus branch from 7a85ff1 to dfd7439 Compare November 26, 2025 13:00
@manu-sncf
Copy link
Contributor Author

manu-sncf commented Nov 26, 2025

@manu-sncf Would you be able to add a test for this?

@justinmc I added a test following the example in packages/flutter/test/widgets/sliver_semantics_test.dart.

@manu-sncf manu-sncf force-pushed the pinned_header_sliver_semantics_focus branch from dfd7439 to 314ca51 Compare November 28, 2025 13:31
@Renzo-Olivares
Copy link
Contributor

Thank you for the contribution @manu-sncf! This change looks reasonable to me and is the same approach we used to solve a similar issue in SliverAppBar #60331. However trying this out change out locally on my pixel 10 pro fold and I am still experiencing this issue. Is there a specific device you tested on?

screen-20251203-165938-1764809950067.mp4

@zemanux
Copy link
Contributor

zemanux commented Dec 4, 2025

Thank you for the contribution @manu-sncf! This change looks reasonable to me and is the same approach we used to solve a similar issue in SliverAppBar #60331. However trying this out change out locally on my pixel 10 pro fold and I am still experiencing this issue. Is there a specific device you tested on?

screen-20251203-165938-1764809950067.mp4

Thank you for your time on this review

I tested on a Pixel 9 Pro emulator and a Pixel 7 Pro real device. I recorded these two videos with the Pixel 7 Pro :

Without fix :

demo_without_fix.mp4

With fix :

demo_with_fix.mp4

FYI: I am migrating all my open PRs from @manu-sncf to @zemanux

@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch from 314ca51 to b1c2289 Compare December 4, 2025 07:58
@zemanux
Copy link
Contributor

zemanux commented Dec 4, 2025

@Renzo-Olivares, I upgraded my flutter engine and rebased the PR from 314ca51 to b1c2289.

I think there is a major regression regarding scrolling semantics on Android. Remove PinnedHeaderSliver from the example, if you attempt to navigate up or down, the focus doesn't move anymore to the previous or next ListTile outside the viewport.

scroll_semantics_issue.mp4

@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch from b1c2289 to c24bd5d Compare December 4, 2025 11:03
@zemanux
Copy link
Contributor

zemanux commented Dec 4, 2025

git bisect points to d18ab0e Fix for PR #174374 - TalkBack does not announce list information

Issue #179450 created.

@Renzo-Olivares
Copy link
Contributor

@zemanux Thank you for catching that regression and filing an issue. Once a fix for that regression lands we can move forward with this change.

@zemanux
Copy link
Contributor

zemanux commented Dec 8, 2025

@Renzo-Olivares, it seems the same issue exists with SliverResizingHeader:

resizable_header.mp4

Here is the result with the same fix applied (config.addTagForChildren(RenderViewport.excludeFromScrolling):

resizable_header_with_fix.mp4

Should I include this fix in the current PR, or would you prefer I create a new issue?

@Renzo-Olivares
Copy link
Contributor

@zemanux looks like a fix for the regression has been merged #179480. Can you verify your fix works after this change?

With regards to SliverResizingHeader, I would generally recommend another PR since it's a separate component. Thank you for catching that issue!

@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch 2 times, most recently from a0555c5 to b45a655 Compare December 10, 2025 14:49
@zemanux
Copy link
Contributor

zemanux commented Dec 10, 2025

@Renzo-Olivares

I created the issue #179687 for SliverResizingHeader.

I confirm the fix works following PR #179480.

I added a new commit (b45a655) to handle an edge case involving a PinnedHeaderSliver positioned in the middle of a list (e.g., a nested list within a SliverMainAxisGroup for a sticky header effect).

Without this fix, config.addTagForChildren(RenderViewport.excludeFromScrolling) add two issues:

  • Focus jumping: The semantics focus skips elements after the PinnedHeaderSliver (resolved via overlap control).
  • Inconsistent traversal: The inner focus order of PinnedHeaderSliver is inconsistent (resolved by using Semantics(container: true, explicitChildNodes: true)).
pinned_header_sliver_without_fix.mp4

Both are now resolved :

pinned_header_sliver_with_fix.mp4
Code sample
import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          const SliverAppBar(
            pinned: true,
            expandedHeight: 100.0,
            title: Text('Pinned Semantic Focus'),
            backgroundColor: Colors.blue,
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
              return ListTile(title: Text('Item $index'), subtitle: const Text('Scroll down then navigate back up'));
            }, childCount: 5),
          ),
          PinnedHeaderSliver(
            child: Semantics(
              child: ColoredBox(
                color: Colors.amber,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      spacing: 8,
                      children: [
                        Padding(padding: const EdgeInsets.only(left: 8.0), child: Text('Pinned Header')),
                        IconButton(onPressed: () {}, icon: Icon(Icons.info)),
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Semantics(container: true, child: Text('Element')),
                    ),
                  ],
                ),
              ),
            ),
          ),
          // The List
          SliverList(
            delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
              return ListTile(title: Text('Item $index'), subtitle: const Text('Scroll down then navigate back up'));
            }, childCount: 50),
          ),
        ],
      ),
    );
  }
}

@Renzo-Olivares
Copy link
Contributor

@zemanux thank you for your patience over the holidays! I just tried the PR out locally with the provided code sample and it works great.

I do wonder if the additional Semantics(container: true, explicitChildNodes: true) widget is necessary. I just tried the change without it and it seems to provide the same results. Traversal works and focus order seems correct on the pinned header. I also tried to remove additional Semantics widgets in the code sample and that also worked the same. Let me know if you also see this same behavior.

screen-20260106-120836-1767730062869.mp4

@zemanux
Copy link
Contributor

zemanux commented Jan 6, 2026

@zemanux thank you for your patience over the holidays! I just tried the PR out locally with the provided code sample and it works great.

I do wonder if the additional Semantics(container: true, explicitChildNodes: true) widget is necessary. I just tried the change without it and it seems to provide the same results. Traversal works and focus order seems correct on the pinned header. I also tried to remove additional Semantics widgets in the code sample and that also worked the same. Let me know if you also see this same behavior.

screen-20260106-120836-1767730062869.mp4

@Renzo-Olivares,
The focus traversal issue only happens when the PinnedHeaderSliver is pinned. Here's a video I just made with the latest rebase (where I removed the Semantics(container: true, explicitChildNodes: true,...).

demo.mp4

@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch from 28d4fe3 to ec5d557 Compare January 6, 2026 22:03
@justinmc justinmc requested a review from Piinks January 13, 2026 23:21
@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch from ec5d557 to 57d0295 Compare January 21, 2026 07:33
@zemanux zemanux force-pushed the pinned_header_sliver_semantics_focus branch from 57d0295 to 962e3f5 Compare February 3, 2026 20:23
Copy link
Contributor

@Renzo-Olivares Renzo-Olivares left a comment

Choose a reason for hiding this comment

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

Thank you for your patience on this one @manu-sncf! I was also able to reproduce the traversal issue when the sliver was pinned as you described. Mostly LGTM with a few comments about testing.

expect(tester.getRect(find.text('PinnedHeaderSliver 2')), rect2);
});

testWidgets('PinnedHeaderSliver: presence of RenderViewport.excludeFromScrolling tag', (
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also have a tests that verifies that inclusion of container:true, and explicitChildNodes: true.

Copy link
Contributor

Choose a reason for hiding this comment

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

I replaced

      expect(
        semantics,
        includesNodeWith(
          tags: {RenderViewport.excludeFromScrolling, RenderViewport.useTwoPaneSemantics},
        ),
      );

by

      final SemanticsNode? semanticNode = semantics
          .nodesWith(label: 'PinnedHeaderSliver')
          .firstOrNull;
      expect(semanticNode?.parent?.tags, {
        RenderViewport.excludeFromScrolling,
        RenderViewport.useTwoPaneSemantics,
      });

Without a wrapping (Semantics(container:true, explicitChildNodes: true, child ...), the test fail.

expect(tester.getRect(find.text('PinnedHeaderSliver 2')), rect2);
});

testWidgets('PinnedHeaderSliver: presence of RenderViewport.excludeFromScrolling tag', (
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe re-name PinnedHeaderSliver: presence of RenderViewport.excludeFromScrolling tag when pinned.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

),
),
);

Copy link
Contributor

@Renzo-Olivares Renzo-Olivares Feb 4, 2026

Choose a reason for hiding this comment

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

We should verify that before the drag the sliver is not pinned and the exclude tag is not present and after the drag that it is pinned.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

@zemanux zemanux deleted the pinned_header_sliver_semantics_focus branch March 13, 2026 20:33
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 14, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 14, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 15, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 15, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 16, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 17, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 17, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 17, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 17, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Mar 18, 2026
Roll Flutter from 732e05dd483c to d117642c18e0 (47 revisions)

flutter/flutter@732e05d...d117642

2026-03-17 [email protected] Roll Skia from fa3bb1f60d99 to dba893a44d7a (1 revision) (flutter/flutter#183783)
2026-03-17 [email protected] [ios][pv]fix admob banner scrollable on ios 18.2 (flutter/flutter#183274)
2026-03-17 [email protected] Roll Packages from 0f2eeae to a9d36fb (2 revisions) (flutter/flutter#183782)
2026-03-17 [email protected] Update goldctl version (flutter/flutter#183538)
2026-03-17 [email protected] Roll Skia from 69be1087807b to fa3bb1f60d99 (1 revision) (flutter/flutter#183779)
2026-03-17 [email protected] Roll Dart SDK from 38dedf00c2cd to 30cdd2634429 (1 revision) (flutter/flutter#183778)
2026-03-17 [email protected] Roll Fuchsia Linux SDK from s7rq9m8tH2aZtX-kP... to zYBvfzIH95BY3cCzL... (flutter/flutter#183777)
2026-03-17 [email protected] Roll Skia from 4ea039236580 to 69be1087807b (2 revisions) (flutter/flutter#183772)
2026-03-17 [email protected] Roll Skia from fb402093cfb5 to 4ea039236580 (1 revision) (flutter/flutter#183770)
2026-03-17 [email protected] Roll Skia from d6bc6d17d637 to fb402093cfb5 (8 revisions) (flutter/flutter#183765)
2026-03-17 [email protected] Roll Dart SDK from ff50ab8ecea4 to 38dedf00c2cd (2 revisions) (flutter/flutter#183764)
2026-03-17 [email protected] Wrap EGL image usage in a GObject (flutter/flutter#183539)
2026-03-17 [email protected] Adds platform_view_test_macos_impeller (flutter/flutter#183760)
2026-03-17 [email protected] Adds flush to metal screenshotter. (flutter/flutter#183758)
2026-03-16 [email protected] Add a platform OpenGL context. (flutter/flutter#183715)
2026-03-16 [email protected] Fix formatting, capitalization, and grammar in activation issue template (flutter/flutter#183061)
2026-03-16 [email protected] Roll Dart SDK from 4a6febbf882e to ff50ab8ecea4 (2 revisions) (flutter/flutter#183739)
2026-03-16 [email protected] docs: add code review guidance to CONTRIBUTING.md (flutter/flutter#182778)
2026-03-16 [email protected] Filter 'waiting for customer response' issues from macOS triage (flutter/flutter#183552)
2026-03-16 [email protected] Adds github action to reset cicd when new branches come (flutter/flutter#183675)
2026-03-16 [email protected] Adds macos impeller complex layout performance test (flutter/flutter#183669)
2026-03-16 [email protected] Roll Dart SDK from b74e5b537d71 to 4a6febbf882e (2 revisions) (flutter/flutter#183695)
2026-03-16 [email protected] Use properties to configure leak_tracking and test_randomization_off in .ci.yaml (flutter/flutter#183605)
2026-03-16 [email protected] [flutter_tools] Avoid File.exists and File.stat, as per enforced lint rule (flutter/flutter#183463)
2026-03-16 [email protected] Properly parse URIs for testPath when the host is running on Windows. (flutter/flutter#176881)
2026-03-16 [email protected] Roll Packages from 91f7c33 to 0f2eeae (6 revisions) (flutter/flutter#183730)
2026-03-16 [email protected] Roll Skia from a6ccaf95c6e0 to d6bc6d17d637 (5 revisions) (flutter/flutter#183726)
2026-03-16 [email protected] Roll Fuchsia Linux SDK from WOfyEFkxf9JX26VS-... to s7rq9m8tH2aZtX-kP... (flutter/flutter#183723)
2026-03-15 [email protected] Roll Skia from 34ace196b838 to a6ccaf95c6e0 (2 revisions) (flutter/flutter#183712)
2026-03-14 [email protected] Roll Fuchsia Linux SDK from vAWG8mRvsQHblDBsy... to WOfyEFkxf9JX26VS-... (flutter/flutter#183694)
2026-03-14 [email protected] Roll Skia from 06106120c6bf to 34ace196b838 (1 revision) (flutter/flutter#183677)
2026-03-14 [email protected] Roll Dart SDK from 6a3dc9d4f881 to b74e5b537d71 (2 revisions) (flutter/flutter#183676)
2026-03-14 [email protected] Add some quality of life improvements to the release GitHub workflows. (flutter/flutter#183658)
2026-03-14 [email protected] Fix RouteAware.didPushNext documentation inaccuracy (flutter/flutter#183097)
2026-03-13 [email protected] Adds complex layout impeller startup benchmark (flutter/flutter#183655)
2026-03-13 [email protected] Adds switch for sdf rendering plus golden tests (flutter/flutter#183543)
2026-03-13 [email protected] Made complex_layout_scroll_perf explicitly skia (flutter/flutter#183663)
2026-03-13 [email protected] Update android integration test to match the current android semantics (flutter/flutter#183548)
2026-03-13 [email protected] Roll Skia from 6c0346103c24 to 06106120c6bf (3 revisions) (flutter/flutter#183654)
2026-03-13 [email protected] Roll Dart SDK from d5f6d3c17499 to 6a3dc9d4f881 (1 revision) (flutter/flutter#183652)
2026-03-13 [email protected] Fix PinnedHeaderSliver semantics focus capture (flutter/flutter#179023)
2026-03-13 [email protected] [a11y][android] In Android 16, sendWindowContentChangeEvent when check state changes (flutter/flutter#183606)
2026-03-13 [email protected] Update gradle utils to know about kgp 2.3.10 constraints (flutter/flutter#183416)
2026-03-13 [email protected] Roll Skia from 029229d8be91 to 6c0346103c24 (5 revisions) (flutter/flutter#183648)
2026-03-13 [email protected] Roll Fuchsia Linux SDK from jJbpv4J_tjW-wuKDq... to vAWG8mRvsQHblDBsy... (flutter/flutter#183646)
2026-03-13 [email protected] [flutter_tools] Support flavors and transformers for shaders (flutter/flutter#181889)
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Projects

Development

Successfully merging this pull request may close these issues.

[Accessibility] PinnedHeaderSliver captures semantic focus before list is fully scrolled

7 participants