1. 문제
아래처럼 TabBarView 위젯의 자식들로 CollectionMine과 CollectionRecommended을 두고, 터치 슬라이드를 통해 탭을 화면 전환하고 싶은 상황입니다. TabBarView는 DefaultTabController 부모로 감싸 별도로 tabController를 구성할 필요 없이 TabBar와 연결하였습니다.
/// Dart
TabBarView(
physics: BouncingScrollPhysics(),
children: [
CollectionMine(),
CollectionRecommended(),
],
),
2-1. 디버깅
우리의 친구 https://chat.openai.com/chat 에게 물어봅니다.
Q. Sliding tab to tab horizontally in flutter using DefaultTabController is not working. why and how to fix it?
There can be several reasons why the sliding tabs feature is not working when using DefaultTabController. Here are a few possibilities:
1. TabController not being properly initialized: Make sure that the TabController is properly initialized and linked to the TabBar and TabBarView. In your case you are using DefaultTabController, but it's not being initialized in the correct context.
2. TabBarView children are not properly linked to the TabBar tabs: The children in the TabBarView need to match the order of the tabs in the TabBar. Make sure that the children in the TabBarView correspond to the tabs in the TabBar.
3. TabBarView children are not in the same tree with DefaultTabController: When using DefaultTabController, it should be an ancestor of both TabBar and TabBarView, and also make sure that the TabController is being passed down to the children via Builder widget if you are using them.
You can fix these issues by making sure to initialize DefaultTabController as the ancestor of both TabBar and TabBarView, and also making sure that the children in the TabBarView correspond to the tabs in the TabBar. Here's an example:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: DefaultTabController( length: 3, child: Scaffold( appBar: AppBar( bottom: TabBar( tabs: [ Tab(text: "Tab 1"), Tab(text: "Tab 2"), Tab(text: "Tab 3"), ], ), ), body: Builder( builder: (context) => TabBarView( controller: DefaultTabController.of(context), children: [ Tab1(), Tab2(), Tab3(), ], ), ), ), ), ); } }
Here, DefaultTabController is being set as the ancestor of both TabBar and TabBarView, and the TabBarView's controller is being set to the `Tab`.
답변을 살펴봐도 제가 사용한 코드와 거의 유사하여 해결책을 찾지는 못했습니다. 두 가지 다른 점이 있다면 Builder를 TabBarView로 감싸주어 contex를 넘겨 controller를 assign하는 것인데요, 이 역시 해결책은 아니었습니다.
이때, TabBarView의 자식들을 Text()로 구성하면 슬라이드가 되는 것을 확인했습니다. 본디 코드에서 children으로 지정한 CollectionMine에는 RefreshIndicator 위젯을 사용하는데요, 아래쪽으로 화면을 pull하여 refresh 함수를 지정하는 위젯인만큼 slide 동작에 영향을 미치지는 않을까 하는 생각에 이르렀습니다.
/// Dart
TabBarView(
physics: BouncingScrollPhysics(),
children: [
Text("123"),
Text("456"),
],
),
2-2. 디버깅
우리의 친구 https://chat.openai.com/chat 에게 다시 물어봅니다.
Q. Sliding tab to tab horizontally in flutter using DefaultTabController is not working if one of TabBarViews is a RefreshIndicator or a GestureDetector.
In Flutter, using a RefreshIndicator or a GestureDetector within a TabBarView can cause issues with scrolling between tabs when using a DefaultTabController. This is because the RefreshIndicator and GestureDetector widgets can consume the swipe gesture used to scroll between tabs. To work around this issue, you can wrap the TabBarView in a NotificationListener and listen for the ScrollEndNotification. When the notification is received, you can check if the user has swiped far enough to trigger a tab change and manually change the tab using the DefaultTabController.
Here is an example of how you might do this:import 'package:flutter/material.dart'; class TabbedPage extends StatefulWidget { @override _TabbedPageState createState() => _TabbedPageState(); } class _TabbedPageState extends State<TabbedPage> with SingleTickerProviderStateMixin { TabController _tabController; double _tabSwipeThreshold = 50.0; @override void initState() { super.initState(); _tabController = TabController(vsync: this, length: 2); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( bottom: TabBar( controller: _tabController, tabs: <Widget>[ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), ], ), ), body: NotificationListener<ScrollEndNotification>( onNotification: (ScrollEndNotification notification) { var dx = notification.metrics.pixels - notification.metrics.extentBefore; if (dx > _tabSwipeThreshold) { _tabController.animateTo(_tabController.index + 1); } else if (dx < -_tabSwipeThreshold) { _tabController.animateTo(_tabController.index - 1); } return true; }, child: TabBarView( controller: _tabController, children: <Widget>[ // Tab 1 content RefreshIndicator( child: ListView(...), onRefresh: () async { // ... }, ), // Tab 2 content GestureDetector( child: Container(...), onTap: () { // ... }, ), ], ), ), ); } }
You can adjust the value of _tabSwipeThreshold as you see fit based on the width of your tabs, or you can use Material Design Swipe Treshold. This is how you can use Material Design Swipe Treshold :import 'package:flutter/material.dart'; class TabbedPage extends StatefulWidget { @override _TabbedPageState createState() => _TabbedPageState(); } class _TabbedPageState extends State<TabbedPage> with Single
3. 해결
원인과 해결책을 찾았습니다. 에상하던대로 RefreshIndicator 또는 GestureDetector로 인해 DefaultTabController의 슬라이드 동작과 충돌했던 것이 이유였습니다. 따라서 자식 위젯에 사용한 RefreshIndicator나 GestureDetector 자체를 빼버리거나, SingleChildScrollView로 감싸주면 됩니다.
댓글