Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upGitHub is where the world builds software
Millions of developers and companies build, ship, and maintain their software on GitHub — the largest and most advanced development platform in the world.
[Tabs] Fix tab indicator flies off issue #65463
Conversation
|
I think we still need the first if case to deal with user tap a tab that are more than one tab away? |
| else if (value == index) | ||
| _currentRect = middle; | ||
| else if (value < index) | ||
| _currentRect = previous == null ? middle : Rect.lerp(middle, previous, index - value); |
chunhtai
Sep 21, 2020
Contributor
isn't this assume index - value is always <1.0 ? in case of user tapp on a tab, this value may be >1.0
isn't this assume index - value is always <1.0 ? in case of user tapp on a tab, this value may be >1.0
nero-angela
Sep 22, 2020
•
Author
Contributor
Yes you are right. index - value can be greater than 1.0. I thought this was the solution for the case of selecting a tab during animation.
I added a gif that the case of user tap a tab that are more than one tab away. It seems no problem, but I'm not sure if this is the case you were talking about or not. If this is not the case of you intended, could you describe more detail situation for reproduce?
Yes you are right. index - value can be greater than 1.0. I thought this was the solution for the case of selecting a tab during animation.
I added a gif that the case of user tap a tab that are more than one tab away. It seems no problem, but I'm not sure if this is the case you were talking about or not. If this is not the case of you intended, could you describe more detail situation for reproduce?
chunhtai
Nov 2, 2020
Contributor
Ah I see, we are doing a negative lerp and using the wrong previous/next rect. They just so happen to cancel each other out.
for example we move from 0 to 2
it will lerp from -1.0 to 1.0, and from rect =1, to dest =2
so this just cancel each other out.
I think this is a dangerous because the lerp value should be from 0.0 to 1.0. We do not guarantee the behavior outside the range. it just so that our current implementation of Rect.lerp somehow works with this corner case. However, it is not guaranteed that it will still work the same in the future.
The correct logic should be as following, let's take the 0 to 2 example
it should lerp from 0.0 to 1.0 from rect 0 to dest 2
Ah I see, we are doing a negative lerp and using the wrong previous/next rect. They just so happen to cancel each other out.
for example we move from 0 to 2
it will lerp from -1.0 to 1.0, and from rect =1, to dest =2
so this just cancel each other out.
I think this is a dangerous because the lerp value should be from 0.0 to 1.0. We do not guarantee the behavior outside the range. it just so that our current implementation of Rect.lerp somehow works with this corner case. However, it is not guaranteed that it will still work the same in the future.
The correct logic should be as following, let's take the 0 to 2 example
it should lerp from 0.0 to 1.0 from rect 0 to dest 2
nero-angela
Nov 12, 2020
•
Author
Contributor
@chunhtai When there are three tabs A, B, C, the image below is a scenario in which the user taps C and then taps B after the animation has progressed 25%.
Here you can see a case which the lerp value is greater than 1, and I think it can be relatively greater or less than 1 depending on which point the lerp is based on.
As this document also says that a value greater than 1 or less than 0 is not an invalid value, I think it is just a difference in mathematical expressions and there is no problem.
Nevertheless, if the lerp value should be between 0 and 1, I think that the function should be newly implemented regardless of the tapping problem during animation.
@chunhtai When there are three tabs A, B, C, the image below is a scenario in which the user taps C and then taps B after the animation has progressed 25%.
Here you can see a case which the lerp value is greater than 1, and I think it can be relatively greater or less than 1 depending on which point the lerp is based on.
As this document also says that a value greater than 1 or less than 0 is not an invalid value, I think it is just a difference in mathematical expressions and there is no problem.
Nevertheless, if the lerp value should be between 0 and 1, I think that the function should be newly implemented regardless of the tapping problem during animation.
chunhtai
Nov 12, 2020
•
Contributor
This seems to not work correctly if the sizes of the tab are not the same.
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
timeDilation = 10.0;
runApp(Test());
}
class Test extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
home: Material(
color: Colors.black,
child: DefaultTabController(
length: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Tap 1 then tap 2.', style: TextStyle(color: Colors.white)),
TabBar(
isScrollable: true,
indicatorSize: TabBarIndicatorSize.tab,
tabs: <Widget>[
Text('-', style: TextStyle(fontSize: 48.0)),
Text('1ljkjlkjlk', style: TextStyle(fontSize: 48.0)),
Text('2', style: TextStyle(fontSize: 48.0)),
],
),
],
),
),
),
);
}
}
This seems to not work correctly if the sizes of the tab are not the same.
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
timeDilation = 10.0;
runApp(Test());
}
class Test extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
home: Material(
color: Colors.black,
child: DefaultTabController(
length: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Tap 1 then tap 2.', style: TextStyle(color: Colors.white)),
TabBar(
isScrollable: true,
indicatorSize: TabBarIndicatorSize.tab,
tabs: <Widget>[
Text('-', style: TextStyle(fontSize: 48.0)),
Text('1ljkjlkjlk', style: TextStyle(fontSize: 48.0)),
Text('2', style: TextStyle(fontSize: 48.0)),
],
),
],
),
),
),
);
}
}
nero-angela
Nov 13, 2020
Author
Contributor
You are right. It doesn't work properly. It seems my current approach is wrong.
Sorry for wasting your time. 🙏
You are right. It doesn't work properly. It seems my current approach is wrong.
Sorry for wasting your time.
|
Hi @nero-angela are you still working on this PR? |
Hi @chunhtai, I'm waitting for your answer about this question. Could you please check my answer? |
|
@chunhtai At the moment of tabbing, the current indicator's position was recorded in the In this regard, is it better to close the current PR and create a new PR to proceed? |
|
I wonder whether we can do it in the following way: we have
We can try to grab the current tab index and the index that is one tab ahead. We can just lerp between this two tabs. For example: value = 1.4, index =5 we know the animation is moving to the right, for example value = 2.3, index = 1 we know the animation is moving to the left, For abs(value - index) < 1.0 , we just keep the logic as is. |
Wow, you are really smart One of the previous tests failed because the indicator's speed was changed normally, and I fixed it correctly. Check out the test-related code here. |
|
@nero-angela |
|
@nero-angela yes, I think that looks good, can you revise this PR with the change? |
|
@chunhtai |
|
LGTM |
af616a0
into
flutter:master



Description
I think the code below is not only wrong, but unnecessary.
flutter/packages/flutter/lib/src/material/tabs.dart
Lines 400 to 404 in 54ade88
The reason why I think it's unnecessary is the below code already covers the case when the animation is running.
flutter/packages/flutter/lib/src/material/tabs.dart
Lines 406 to 421 in 54ade88
And as you can see the below code, it is implemented by putting
_currentRectinRect.lerp()and putting the result back in_currentRect. Implemented in this way, the indicator will performs an acceleration motion. I prepared a dart pad to help you understand.flutter/packages/flutter/lib/src/material/tabs.dart
Line 403 in e682ec7
In the test, I think below comment is mentioned because the indicator performs acceleration motion.
flutter/packages/flutter/test/material/tabs_test.dart
Line 1656 in e682ec7
I have also identified the cause of the disappearance of the indicator, but I will skip this because the problematic code is replaced with the existing code.
Related Issues
Fixes #48000
Tests
I added the following test:
I fixed the following test:
flutter/packages/flutter/test/material/tabs_test.dart
Lines 1656 to 1661 in e682ec7
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.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.