Skip to content

Repaint NavigationIndicator's host Material when its animation ticks - #187802

Closed
theprantadutta wants to merge 3 commits into
flutter:masterfrom
theprantadutta:fix/navigation-indicator-remote-repaint
Closed

theprantadutta wants to merge 3 commits into
flutter:masterfrom
theprantadutta:fix/navigation-indicator-remote-repaint

Conversation

@theprantadutta

Copy link
Copy Markdown
Contributor

NavigationIndicator draws its background with an Ink widget, which paints on the nearest ancestor Material rather than on its own render object. When the selected index changes without a pointer interaction (for example, programmatically alongside an IndexedStack), nothing notifies that Material, so it keeps showing the indicator's previous frame. In a NavigationDrawer — where the host Material sits outside the destination ListView — the highlight visibly sticks to the old destination until a hover, click, or window resize forces a repaint.

This PR applies the fix dkwingsmt verified in the issue thread: notify the indicator's MaterialInkController whenever the indicator animation ticks. On the idiomatic-ness question raised there: markNeedsPaint() is part of the public MaterialInkController interface, documented as "Notifies the controller that one of its ink features needs to repaint", and it is the same mechanism ink features like InkHighlight and InkSplash use when their state changes — so this seemed like the most direct expression of the intent.

The regression test deliberately avoids the paints matcher (which forces a repaint and would mask the staleness). Instead it changes selectedIndex programmatically, pumps a frame up to EnginePhase.layout, and asserts the indicator's host Material render object is marked as needing paint. The test fails without the one-line fix and passes with it. The full navigation_drawer_test.dart, navigation_bar_test.dart, and navigation_rail_test.dart suites pass (NavigationIndicator is shared by all three widgets).

Fixes #180359

Pre-launch Checklist

NavigationIndicator draws its background with an Ink widget, which
paints on the nearest ancestor Material rather than on its own render
object. When the selected index changes without a pointer interaction
(for example, programmatically alongside an IndexedStack), nothing
notifies that Material, so it keeps showing the indicator's previous
frame; in a NavigationDrawer the highlight visibly sticks to the old
destination until a hover, click, or resize forces a repaint.

Notify the indicator's MaterialInkController whenever the indicator
animation ticks, the same way ink features such as InkHighlight request
repaints when their state changes.

Fixes flutter#180359

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request ensures that the navigation indicator repaints when the selected index changes programmatically by calling Material.of(context).markNeedsPaint() during animation ticks, and adds a regression test to verify this behavior. Feedback suggests using Material.maybeOf(context)?.markNeedsPaint() instead to prevent potential runtime exceptions in environments where a Material ancestor is not present.

Comment thread packages/flutter/lib/src/material/navigation_bar.dart
@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages labels Jun 10, 2026
@theprantadutta

Copy link
Copy Markdown
Contributor Author

Regarding the code freeze check: this is a one-line fix for a regression introduced by #164484 (the indicator stopped repainting on programmatic selection changes), and the approach was verified by dkwingsmt in #180359 before this PR was opened. If it qualifies for override: code freeze I'm happy to proceed here — otherwise I'm glad to port it to material_ui in flutter/packages instead, whichever the team prefers.

@dkwingsmt
dkwingsmt self-requested a review June 17, 2026 18:16
@Piinks Piinks added the Decoupling: Not ready to port yet Instructions will be provided when this is ready to move to flutter/packages. label Jun 24, 2026
@Piinks

Piinks commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

I've marked this PR as not ready to port to flutter/packages yet.
We'll provide instructions to move this change over to material_ui/cupertino_ui once ready to receive PRs. Thank you!

@Piinks Piinks added the CICD Run CI/CD label Jul 15, 2026
dkwingsmt
dkwingsmt previously approved these changes Jul 27, 2026

@dkwingsmt dkwingsmt 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.

Fantastic documentation and unit test! Thank you very much!

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Jul 27, 2026
@dkwingsmt dkwingsmt added the CICD Run CI/CD label Jul 27, 2026
@dkwingsmt

Copy link
Copy Markdown
Contributor

@QuncCccccc Can you make a 2nd review?

@dkwingsmt
dkwingsmt requested a review from QuncCccccc July 27, 2026 22:36
QuncCccccc
QuncCccccc previously approved these changes Aug 5, 2026

@QuncCccccc QuncCccccc 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.

LGTM with one super nit. Thanks a lot for your contribution!

Comment thread packages/flutter/lib/src/material/navigation_bar.dart
testWidgets('Indicator repaints when selectedIndex changes without pointer interaction', (
WidgetTester tester,
) async {
// Regression test for https://github.com/flutter/flutter/issues/180359.

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.

super nit: I usually will put this comment above the test:)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved the regression test reference above the test in 1e5b7df — thanks, and thanks for the second review. Understood on the freeze; I'll watch for the porting instructions once the decoupling lands.

@dkwingsmt

Copy link
Copy Markdown
Contributor

Thanks for your contribution! This PR has reached completion, however we're not able to merge this PR for the moment due to the Material/Cupertino code freeze (#184093). As soon as the decoupling is complete, we will post a way to port this PR to the new packages to land. In the meantime, I'll convert this PR to a draft and apply a label so that we can quickly find it when the freeze is lifted.

(Feel free to address the nit comment if you feel like to, either here in the draft or in the new PR.)

@dkwingsmt
dkwingsmt marked this pull request as draft August 5, 2026 23:33
@dkwingsmt dkwingsmt added the waiting for code freeze This PR is waiting for a code freeze to resolve. label Aug 5, 2026
@theprantadutta
theprantadutta dismissed stale reviews from QuncCccccc and dkwingsmt via 1e5b7df August 12, 2026 16:40
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 12, 2026
@dkwingsmt

Copy link
Copy Markdown
Contributor

If you would like to return to this, material_ui and cupertino_ui are now accepting contributions. :)
Guidance and instructions for easily porting over can be found in #188444. Thank you for the contribution and for waiting!

@dkwingsmt dkwingsmt added Decoupling: Port to flutter/packages This PR is ready to be ported to flutter/packages. We will provide instructions to do so. and removed Decoupling: Not ready to port yet Instructions will be provided when this is ready to move to flutter/packages. labels Sep 24, 2026
@theprantadutta

Copy link
Copy Markdown
Contributor Author

Thanks @dkwingsmt — ported to material_ui in flutter/packages#13010 following #188444. Closing this one in favour of that.

auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 2, 2026
…without pointer input (#13010)

Port of flutter/flutter#187802 to `material_ui`, following the process in flutter/flutter#188444. The original PR was approved by dkwingsmt and QuncCccccc but couldn't land because of the Material/Cupertino code freeze.

`NavigationIndicator` draws its indicator with an `Ink`, which paints on the nearest ancestor `Material` rather than locally. When the indicator animates without an accompanying pointer interaction — for example when `selectedIndex` is changed programmatically — nothing tells that `Material` to repaint, so it keeps showing the indicator's previous frame. The fix calls `Material.of(context).markNeedsPaint()` on each animation tick.

The regression test pumps a `NavigationDrawer`, changes `selectedIndex` from outside without any pointer events, and verifies the indicator repaints. I checked it fails with the one-line fix removed and passes with it, in its new location under `packages/material_ui/test/`.

The two original commits were cherry-picked without merge commits, as the porting guide describes; rename detection placed them at `lib/src/navigation_bar.dart` and `test/navigation_drawer_test.dart` with no conflicts. The only new commit adds the pending changelog entry (`version: patch`).

Fixes flutter/flutter#180359

## Pre-Review Checklist

I used AI tooling while working on this, and reviewed and tested all of it myself.

[^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Decoupling: Port to flutter/packages This PR is ready to be ported to flutter/packages. We will provide instructions to do so. framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages waiting for code freeze This PR is waiting for a code freeze to resolve.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NavigationDrawer highlight is wrong when changing index from elsewhere

4 participants