Skip to content
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

[Material] Update TabController to support dynamic Tabs #30884

Merged
merged 15 commits into from Apr 29, 2019

Conversation

@johnsonmh
Copy link
Contributor

@johnsonmh johnsonmh commented Apr 11, 2019

Description

Because DefaultTabController creates its TabController once (in initState), it is currently impossible to:

  1. Modify the number of tabs you have after the first build.
  2. Load tabs dynamically/asynchronous.
  3. Update a TabBar and hot reload the changes.

This change adds an override to didUpdateWidget in DefaultTabController, it will detect updates to DefaultTabController.length and update the DefaultTabController.controller accordingly.

After the changes here, we can now do:
giphy

Related Issues

Tests

I added the following tests:

  • Build a TabBar with three tabs, update it to have two tabs, then one tab, then two tabs again. App should never crash and DefaultTabController should be updated accordingly.
  • When there is only one tab in a TabBar, it renders with the proper color (regression test for #15008).

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 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

Does your PR require Flutter developers to manually update their apps to accommodate your change?

@HansMuller
Copy link
Contributor

@HansMuller HansMuller commented Apr 23, 2019

This looks like a good change: DefaultTabController.didUpdateWidget.didUpdateWidget definitely should DTRT when rebuilt with a new length.

I'd prefer to not make TabController.copyWith public. It introduces a problem with the lifetime the TabController's AnimationController, since TabController.dispose() will now apply to the original and all copies. Should be easy enough to deal with that in this one case, but I don't think we want to face the general problem (at least not yet).

@johnsonmh johnsonmh changed the title [WIP] Update TabController to support dynamic Tabs [Material] Update TabController to support dynamic Tabs Apr 24, 2019
rami-a
rami-a approved these changes Apr 24, 2019
Copy link
Member

@rami-a rami-a left a comment

LGTM, just small comments

packages/flutter/lib/src/material/tab_controller.dart Outdated Show resolved Hide resolved
packages/flutter/lib/src/material/tab_controller.dart Outdated Show resolved Hide resolved
packages/flutter/lib/src/material/tab_controller.dart Outdated Show resolved Hide resolved
Copy link
Contributor

@HansMuller HansMuller left a comment

Looks good with a few cleanup suggestions.

packages/flutter/lib/src/material/tab_controller.dart Outdated Show resolved Hide resolved
packages/flutter/lib/src/material/tabs.dart Outdated Show resolved Hide resolved
Copy link
Contributor

@HansMuller HansMuller left a comment

LGTM with one small change.

packages/flutter/lib/src/material/tab_controller.dart Outdated Show resolved Hide resolved
@johnsonmh johnsonmh merged commit 5412ef0 into flutter:master Apr 29, 2019
35 checks passed
@johnsonmh johnsonmh deleted the fix-defaultTabController branch Apr 29, 2019
johnsonmh added a commit that referenced this issue May 9, 2019
@JamalBelilet
Copy link

@JamalBelilet JamalBelilet commented May 15, 2019

Can you please merge this to the dev branch.

@wzieba
Copy link

@wzieba wzieba commented May 24, 2019

Thanks @johnsonmh for your work on this!

Can we know ETA for releasing this?

@fellow7000
Copy link

@fellow7000 fellow7000 commented Jun 2, 2019

This will be great to have it in the very nearest future, stuck with this problem today :-/

@johnsonmh any news on that?..

@johnsonmh
Copy link
Contributor Author

@johnsonmh johnsonmh commented Jun 3, 2019

Hi all! Glad this work is helpful to people.

This PR was merged sucessfully into master about a month ago. It is now following the regular release process. Since it's been about a month, it should be on the beta channel soon. And, keep in mind, you can start using this feature immediately by switching to the master channel.

@fellow7000
Copy link

@fellow7000 fellow7000 commented Jun 3, 2019

@johnsonmh Hi! Thanks for prompt feedback!

Just changes to master and realized that this does not help me much, because I use TabController, not the DefaultTabController as I need to know the index of the selected Tab on screen.

Looks like your fix does not work for TabController (but it works for default one) :-/ Any ideas on that?

@johnsonmh
Copy link
Contributor Author

@johnsonmh johnsonmh commented Jun 6, 2019

@fellow7000 Sorry, I don't know how you would make this work with a regular TabController.

If all you need is the index of the currently selected tab, you could do that pretty easily with a DefaultTabController by adding a int _selectedIndex on your state object, and update it in the TabBar.onTap callback.

Something like:

int _selectedIndex = 0;

...

DefaultTabController(
  length: length,
  child: TabBar(
    tabs: _tabs,
    onTap: (i) => setState(() => _selectedIndex = i),
  ),
),

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.