Skip to content

Commit 05477fa

Browse files
authored
Merge pull request #4 from cb-cloud/fix_tab_behavior
Fix tab behavior
2 parents da6b827 + 5073144 commit 05477fa

File tree

5 files changed

+71
-40
lines changed

5 files changed

+71
-40
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.0.1
2+
FIX
3+
- Added `indicatorHeight` property to `InfintieScrollTabView`. It will override indicator height if specified non-null value.
4+
- The tabs now prevent double tap.
5+
- Fixed a bug that tapping tab causes changing page to unexpected index sometime.
16
## 1.0.0
27
FEAT
38
- Changed internal structure about indicator. It considers specified `separator`'s size now.

Diff for: example/pubspec.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ packages:
6666
path: ".."
6767
relative: true
6868
source: path
69-
version: "1.0.0"
69+
version: "1.0.1"
7070
matcher:
7171
dependency: transitive
7272
description:

Diff for: lib/src/infinite_scroll_tab_view.dart

+14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class InfiniteScrollTabView extends StatelessWidget {
2929
this.backgroundColor,
3030
this.onPageChanged,
3131
this.indicatorColor = Colors.pinkAccent,
32+
this.indicatorHeight,
3233
this.tabHeight = 44.0,
3334
this.tabPadding = 12.0,
3435
}) : super(key: key);
@@ -83,6 +84,14 @@ class InfiniteScrollTabView extends StatelessWidget {
8384
/// Defaults to [Colors.pinkAccent], and must not be null.
8485
final Color indicatorColor;
8586

87+
/// The height of indicator.
88+
///
89+
/// If this is null, the indicator height is aligned to [separator] height, or
90+
/// it also null, then fallbacks to 2.0.
91+
///
92+
/// This must 1.0 or higher.
93+
final double? indicatorHeight;
94+
8695
/// The height of tab contents.
8796
///
8897
/// Defaults to 44.0.
@@ -97,6 +106,10 @@ class InfiniteScrollTabView extends StatelessWidget {
97106

98107
@override
99108
Widget build(BuildContext context) {
109+
if (indicatorHeight != null) {
110+
assert(indicatorHeight! >= 1.0);
111+
}
112+
100113
return LayoutBuilder(
101114
builder: (context, constraint) => InnerInfiniteScrollTabView(
102115
size: constraint.biggest,
@@ -111,6 +124,7 @@ class InfiniteScrollTabView extends StatelessWidget {
111124
backgroundColor: backgroundColor,
112125
onPageChanged: onPageChanged,
113126
indicatorColor: indicatorColor,
127+
indicatorHeight: indicatorHeight,
114128
defaultLocale: Localizations.localeOf(context),
115129
tabHeight: tabHeight,
116130
tabPadding: tabPadding,

Diff for: lib/src/inner_infinite_scroll_tab_view.dart

+50-38
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class InnerInfiniteScrollTabView extends StatefulWidget {
2424
this.backgroundColor,
2525
this.onPageChanged,
2626
required this.indicatorColor,
27+
this.indicatorHeight,
2728
required this.defaultLocale,
2829
required this.tabHeight,
2930
required this.tabPadding,
@@ -41,6 +42,7 @@ class InnerInfiniteScrollTabView extends StatefulWidget {
4142
final Color? backgroundColor;
4243
final ValueChanged<int>? onPageChanged;
4344
final Color indicatorColor;
45+
final double? indicatorHeight;
4446
final Locale defaultLocale;
4547
final double tabHeight;
4648
final double tabPadding;
@@ -58,7 +60,7 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
5860
);
5961
late final _pageController = CycledScrollController();
6062

61-
bool _isContentChangingByTab = false;
63+
final ValueNotifier<bool> _isContentChangingByTab = ValueNotifier(false);
6264
bool _isTabForceScrolling = false;
6365

6466
late double _previousTextScaleFactor = widget.textScaleFactor;
@@ -85,7 +87,8 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
8587
final List<Tween<double>> _tabSizeTweens = [];
8688
List<Tween<double>> get tabSizeTweens => _tabSizeTweens;
8789

88-
double get indicatorWidth => widget.separator?.width ?? 2.0;
90+
double get indicatorWidth =>
91+
widget.indicatorHeight ?? widget.separator?.width ?? 2.0;
8992

9093
late final _indicatorAnimationController =
9194
AnimationController(vsync: this, duration: _tabAnimationDuration)
@@ -182,7 +185,7 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
182185
});
183186

184187
_pageController.addListener(() {
185-
if (_isContentChangingByTab) return;
188+
if (_isContentChangingByTab.value) return;
186189

187190
final currentIndexDouble = _pageController.offset / widget.size.width;
188191
final currentIndex = currentIndexDouble.floor();
@@ -210,11 +213,12 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
210213
}
211214

212215
void _onTapTab(int modIndex, int rawIndex) async {
216+
_isContentChangingByTab.value = true;
217+
213218
widget.onTabTap?.call(modIndex);
214219
widget.onPageChanged?.call(modIndex);
215220

216221
HapticFeedback.selectionClick();
217-
_selectedIndex.value = modIndex;
218222
_isTabPositionAligned.value = true;
219223

220224
final sizeOnIndex = _calculateTabSizeFromIndex(modIndex);
@@ -236,25 +240,24 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
236240
.animate(_indicatorAnimationController);
237241
_indicatorAnimationController.forward(from: 0);
238242

239-
_isContentChangingByTab = true;
240243
// 現在のスクロール位置とページインデックスを取得
241244
final currentOffset = _pageController.offset;
242-
final currentModIndex =
243-
(currentOffset ~/ widget.size.width) % widget.contentLength;
244245

245246
// 選択したページまでの距離を計算する
246247
// modの境界をまたぐ場合を考慮して、近い方向を指すように正負を調整する
247248
final move = calculateMoveIndexDistance(
248-
currentModIndex, modIndex, widget.contentLength);
249+
_selectedIndex.value, modIndex, widget.contentLength);
249250
final targetPageOffset = currentOffset + move * widget.size.width;
250251

252+
_selectedIndex.value = modIndex;
253+
251254
await _pageController.animateTo(
252255
targetPageOffset,
253256
duration: _tabAnimationDuration,
254257
curve: Curves.ease,
255258
);
256259

257-
_isContentChangingByTab = false;
260+
_isContentChangingByTab.value = false;
258261
}
259262

260263
@override
@@ -265,35 +268,12 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
265268
children: [
266269
SizedBox(
267270
height: widget.tabHeight + (widget.separator?.width ?? 0),
268-
child: CycledListView.builder(
269-
scrollDirection: Axis.horizontal,
270-
controller: _tabController,
271-
contentCount: widget.contentLength,
272-
itemBuilder: (context, modIndex, rawIndex) {
273-
return Material(
274-
color: widget.backgroundColor,
275-
child: InkWell(
276-
onTap: () => _onTapTab(modIndex, rawIndex),
277-
child: ValueListenableBuilder<int>(
278-
valueListenable: _selectedIndex,
279-
builder: (context, index, _) =>
280-
ValueListenableBuilder<bool>(
281-
valueListenable: _isTabPositionAligned,
282-
builder: (context, tab, _) => _TabContent(
283-
isTabPositionAligned: tab,
284-
selectedIndex: index,
285-
indicatorColor: widget.indicatorColor,
286-
tabPadding: widget.tabPadding,
287-
modIndex: modIndex,
288-
tabBuilder: widget.tabBuilder,
289-
separator: widget.separator,
290-
indicatorWidth: indicatorWidth,
291-
),
292-
),
293-
),
294-
),
295-
);
296-
},
271+
child: ValueListenableBuilder<bool>(
272+
valueListenable: _isContentChangingByTab,
273+
builder: (context, value, _) => AbsorbPointer(
274+
absorbing: value,
275+
child: _buildTabSection(),
276+
),
297277
),
298278
),
299279
Positioned(
@@ -334,6 +314,38 @@ class InnerInfiniteScrollTabViewState extends State<InnerInfiniteScrollTabView>
334314
);
335315
}
336316

317+
Widget _buildTabSection() {
318+
return CycledListView.builder(
319+
scrollDirection: Axis.horizontal,
320+
controller: _tabController,
321+
contentCount: widget.contentLength,
322+
itemBuilder: (context, modIndex, rawIndex) {
323+
return Material(
324+
color: widget.backgroundColor,
325+
child: InkWell(
326+
onTap: () => _onTapTab(modIndex, rawIndex),
327+
child: ValueListenableBuilder<int>(
328+
valueListenable: _selectedIndex,
329+
builder: (context, index, _) => ValueListenableBuilder<bool>(
330+
valueListenable: _isTabPositionAligned,
331+
builder: (context, tab, _) => _TabContent(
332+
isTabPositionAligned: tab,
333+
selectedIndex: index,
334+
indicatorColor: widget.indicatorColor,
335+
tabPadding: widget.tabPadding,
336+
modIndex: modIndex,
337+
tabBuilder: widget.tabBuilder,
338+
separator: widget.separator,
339+
indicatorWidth: indicatorWidth,
340+
),
341+
),
342+
),
343+
),
344+
);
345+
},
346+
);
347+
}
348+
337349
@override
338350
void dispose() {
339351
_tabController.dispose();

Diff for: pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: infinite_scroll_tab_view
22
description: A Flutter package for tab view component that can scroll infinitely.
3-
version: 1.0.0
3+
version: 1.0.1
44
repository: https://github.com/cb-cloud/flutter_infinite_scroll_tab_view
55

66
environment:

0 commit comments

Comments
 (0)