Skip to content

Prevent material switch from recreating its render object when it becomes disabled#61398

Merged
fluttergithubbot merged 3 commits intoflutter:masterfrom
LongCatIsLooong:actions-keep-tree-shape
Aug 17, 2020
Merged

Prevent material switch from recreating its render object when it becomes disabled#61398
fluttergithubbot merged 3 commits intoflutter:masterfrom
LongCatIsLooong:actions-keep-tree-shape

Conversation

@LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented Jul 13, 2020

Description

FocusableActionDetector changes the shape of the tree so _SwitchRenderObjectWidget needs a GlobalKey to get reused. Preferred this GlobalKey solution over changing the implementation of FocusableActionDetector, because that latter would change the semantics of many other widgets.

Related Issues

fixes #61247

Tests

I added the following tests:

Material switch should not recreate its render object when disabled

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

  • No, no existing tests failed, so this is not a breaking change.

@fluttergithubbot fluttergithubbot added f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels Jul 13, 2020
child: Builder(
builder: (BuildContext context) {
return _SwitchRenderObjectWidget(
// FocusableActionDetector changes the shape of the tree when the
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we instead fix FocusableActionDetector to not remove the Actions and Shortcuts widgets when disabled, and instead just empty out their maps? There is some performance cost to building them, but if they cause churn in the tree, that could be offset by not causing it anymore.

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Jul 14, 2020

Choose a reason for hiding this comment

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

It would break some tests because that introduces a 1 frame delay to descendant Focus's semantics (isFocusable) . Currently since we change the shape of the tree, a new Focus widget gets inflated so there's no delay (line 1090):

@override
Widget build(BuildContext context) {
Widget child = MouseRegion(
onEnter: _handleMouseEnter,
onExit: _handleMouseExit,
cursor: widget.mouseCursor,
child: Focus(
focusNode: widget.focusNode,
autofocus: widget.autofocus,
canRequestFocus: _canRequestFocus,
onFocusChange: _handleFocusChange,
child: widget.child,
),
);
if (widget.enabled && widget.actions != null && widget.actions.isNotEmpty) {
child = Actions(actions: widget.actions, child: child);
}
if (widget.enabled && widget.shortcuts != null && widget.shortcuts.isNotEmpty) {
child = Shortcuts(shortcuts: widget.shortcuts, child: child);
}
return child;
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(Is this expected?)

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, I would think that anything that cares about the focus changing shouldn't care about the 1 frame delay, since focus changes already happen in a microtask, so that already happens often. And semantics shouldn't care about a 1 frame delay either.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I added that part because the focus changes were increasing a build benchmark, and I was trying to reduce the number of built items for things that were disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If a switch is disabled then isFocusable should be removed from its semantics flags in the same frame, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

The focus itself won't actually be removed until the microtask runs, so if the semantics removes it immediately, it might actually be early (and wrong until the task runs).

SemanticsFlag.hasCheckedState,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isInMutuallyExclusiveGroup,
SemanticsFlag.isFocusable, // This flag is delayed by 1 frame.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated. But it still seems confusing to me that when the UI is disabled the semantics is telling us the component is focusable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, ideally it would be resolved immediately, but it causes too much of a performance hit to update focus while the tree is rebuilt, and would mean that sometimes (during the build) two things could have focus at the same time, or that nothing has focus, which complicates a lot of logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would it be possible to update the focus tree after we finalize the layout (instead of in a post-frame callback)?

@LongCatIsLooong
Copy link
Contributor Author

@gspencergoog updated the PR. Could you take another look?

SemanticsFlag.hasCheckedState,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isInMutuallyExclusiveGroup,
SemanticsFlag.isFocusable, // This flag is delayed by 1 frame.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, ideally it would be resolved immediately, but it causes too much of a performance hit to update focus while the tree is rebuilt, and would mean that sometimes (during the build) two things could have focus at the same time, or that nothing has focus, which complicates a lot of logic.

@fluttergithubbot fluttergithubbot merged commit 579cab8 into flutter:master Aug 17, 2020
@LongCatIsLooong LongCatIsLooong deleted the actions-keep-tree-shape branch August 18, 2020 17:38
LongCatIsLooong added a commit that referenced this pull request Aug 18, 2020
LongCatIsLooong added a commit that referenced this pull request Aug 21, 2020
LongCatIsLooong added a commit to LongCatIsLooong/flutter that referenced this pull request Aug 21, 2020
LongCatIsLooong added a commit that referenced this pull request Aug 21, 2020
smadey pushed a commit to smadey/flutter that referenced this pull request Aug 27, 2020
smadey pushed a commit to smadey/flutter that referenced this pull request Aug 27, 2020
smadey pushed a commit to smadey/flutter that referenced this pull request Aug 27, 2020
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Material switch toggle animation absent when disabling the switch in the same rebuild

4 participants