-
Notifications
You must be signed in to change notification settings - Fork 28.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add onHover and onFocusChange callbacks for TabBar #164816
Conversation
@@ -844,6 +844,12 @@ class _TabBarScrollController extends ScrollController { | |||
} | |||
} | |||
|
|||
/// Signature for [TabBar] callbacks that report that an underlying value has | |||
/// changed for a given [Tab] at `index`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe give an example for what value
might be for each case. e.g. for onHover
the value means hovered
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some more docs! :)
/// changed for a given [Tab] at `index`. | ||
/// | ||
/// Used for [TabBar.onHover] and [TabBar.onFocusChange] callbacks. | ||
typedef TabValueChanged<T> = void Function(T value, int index); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Value seems a bit weird in this context. May be TabStateChanged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this can only happen for one tab at a time should we change the function signature to just an index?
typedef TabChanged = ValueChanged<int?>;
This may be cleaning when, lets say changing the focus, you will only call this method once with the current affected index, instead of twice: one with true the other with false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this can only happen for one tab at a time should we change the function signature to just an index?
Good question! It can happen for multiple tabs at once, like in the test cases here. If focus/hover moves directly from one tab to another, they both receive callbacks for the events of entering and exiting those states.
Value seems a bit weird in this context. May be TabStateChanged
I want to stick with value
since it is consistently used for focus and hover callbacks across the framework. This is really similar to the ValueChanged callback that they all use: https://api.flutter.dev/flutter/foundation/ValueChanged.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they both receive callbacks for the events of entering and exiting those states.
I was suggesting the callback can just have the current hovered/focused tab as input.
I imaging the use case is to change styling of Tab of hovered/focused tab. The current callback will be called twice when the focused tab change for example. It is unclear to me at which callback they should modify their Tabs.
My suggestion is to just call the callback with the current focused tab one time since the developer mostly likely only want to know which one is currently focused
bassically instead of
int? currentFocusedIndex;
onFocused: (bool state, int index) {
if (!state) {
if (currentFocusedIndex == index) {
currentFocusedIndex = null;
}
return;
}
currentFocusedIndex = index
}
we should just provide api like this
int? currentFocusedIndex;
onFocused: (int? index) {
currentFocusedIndex = index
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latter example does not account for focus being lost, or hover exiting. The developer wants to be able to respond to these states as well. Just passing the index does not supply the context of what the state is, and differs from current convention for these callbacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in case that no tab is hovered or focused, the callback will call with index equals to null, or -1 whichever we document on the callback.
Do we have existing convention for this kind of callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it would, if no tab is hovered or focused, no callback is not called. What would trigger the callback if no event has occurred?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM:)
Thanks for the review @QuncCccccc! I also have some notes from syncing with @chunhtai on this today. I need to resolve the analysis failure, and add some sample code. 👍 |
setState(() { | ||
focusedIndex = switch (value) { | ||
true => index, | ||
false => null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to worry about cases where false is called after true?
for example switch from focus from tab 1-> tab2
whether tabs 1 false may be called after tab 2 true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't we should probably document this on the api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to worry about cases where false is called after true?
I don't think so, I've tested it, I was curious about the same exact thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for focus it is probably fine.
for hover I looked at the code, onExit is called before onEnter
lastAnnotations.forEach((MouseTrackerAnnotation annotation, Matrix4 transform) { |
we should still document this on the api though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah gotcha! Added!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, except for documenting the behavior mentioned in #164816 (comment)
autosubmit label was removed for flutter/flutter/164816, because - The status or check suite Linux analyze has failed. Please fix the issues identified (or deflake) before re-applying this label. |
autosubmit label was removed for flutter/flutter/164816, because - The status or check suite Linux analyze has failed. Please fix the issues identified (or deflake) before re-applying this label. |
autosubmit label was removed for flutter/flutter/164816, because - The status or check suite Google testing has failed. Please fix the issues identified (or deflake) before re-applying this label. |
Fixes #159444
Fixes #146089
This adds callbacks to TabBar for onHover and onFocusChange.
They pipe through to the underlying Inkwell widget that is wrapped around each Tab of the TabBar during build.
Alternatives
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.