Files
hash-wallet/lib/new-ui/widgets/line_tab_switcher.dart
T
2026-06-04 04:35:29 +02:00

159 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class LineTabSwitcher extends StatefulWidget {
const LineTabSwitcher({
super.key,
required this.tabs,
required this.onTabChange,
required this.selectedTab,
});
final List<String> tabs;
final void Function(int index) onTabChange;
final int selectedTab;
@override
State<LineTabSwitcher> createState() => _LineTabSwitcherState();
}
class _LineTabSwitcherState extends State<LineTabSwitcher> {
List<GlobalKey> textWidgetKeys = [];
List<Size> textWidgetSizes = [];
double totalWidth = 0;
final double itemPadding = 16;
final double barPadding = 8;
bool textWidgetsMeasured = false;
@override
void didUpdateWidget(covariant LineTabSwitcher oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.tabs.length != widget.tabs.length) {
textWidgetKeys = List.generate(widget.tabs.length, (_) => GlobalKey());
textWidgetSizes = [];
totalWidth = 0;
textWidgetsMeasured = false;
WidgetsBinding.instance.addPostFrameCallback((_) => measure());
}
}
double _calcBarLeft() {
double left = 0;
if (textWidgetKeys.isEmpty || textWidgetSizes.isEmpty) {
return 0;
}
for (int i = 0; i < widget.selectedTab; i++) {
left += textWidgetSizes[i].width + itemPadding;
}
left += barPadding;
return left;
}
@override
void initState() {
super.initState();
textWidgetKeys = List.generate(widget.tabs.length, (index) => GlobalKey());
WidgetsBinding.instance.addPostFrameCallback((_) => measure());
}
void measure() {
if(textWidgetsMeasured) return;
setState(() {
textWidgetSizes = textWidgetKeys
.map((k) => k.currentContext!.size)
.whereType<Size>()
.toList();
for(final size in textWidgetSizes) {
totalWidth += size.width+itemPadding;
}
totalWidth += barPadding;
textWidgetsMeasured = true;
});
}
@override
Widget build(BuildContext context) {
if (!textWidgetsMeasured) {
WidgetsBinding.instance.addPostFrameCallback((_) => measure());
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 28,
child: Row(
children: widget.tabs.map((item){
final index = widget.tabs.indexOf(item);
return GestureDetector(
onTap: () {
widget.onTabChange(index);
},
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedDefaultTextStyle(
duration: Duration(milliseconds: 150),
style: DefaultTextStyle.of(context).style.copyWith(
inherit: true,
fontSize: 16,
fontWeight: FontWeight.w500,
color: widget.selectedTab == index
? Theme.of(context).colorScheme.onSurface
: Theme.of(context).colorScheme.onSurfaceVariant,
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: itemPadding/2),
child: Text(
item,
key: textWidgetKeys[index],
),
),
),
],
),
);
}).toList()
)
),
if(widget.tabs.length > 1)
Container(
width: totalWidth,
height: 2,
child: Stack(
children: [
AnimatedPositioned(
curve: Curves.easeOut,
left: _calcBarLeft(),
bottom: 0,
duration: Duration(milliseconds: 150),
child: AnimatedSize(
duration: Duration(milliseconds: 150),
child: Container(
height: 2,
width: textWidgetSizes.isEmpty
? 0
: textWidgetSizes[widget.selectedTab].width,
color: Theme.of(context).colorScheme.onSurface,
),
),
),
],
),
),
],
);
}
}