stack_wallet/lib/widgets/custom_tab_view.dart

160 lines
5.2 KiB
Dart
Raw Permalink Normal View History

2023-05-26 21:21:16 +00:00
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
import 'package:flutter/material.dart';
2024-05-27 23:56:22 +00:00
import '../themes/stack_colors.dart';
import '../utilities/text_styles.dart';
class CustomTabView extends StatefulWidget {
const CustomTabView({
2024-05-27 23:56:22 +00:00
super.key,
required this.titles,
required this.children,
this.initialIndex = 0,
this.childPadding,
2024-05-27 23:56:22 +00:00
}) : assert(titles.length == children.length);
final List<String> titles;
final List<Widget> children;
final int initialIndex;
final EdgeInsets? childPadding;
@override
State<CustomTabView> createState() => _CustomTabViewState();
}
class _CustomTabViewState extends State<CustomTabView> {
late int _selectedIndex;
static const duration = Duration(milliseconds: 250);
@override
void initState() {
_selectedIndex = widget.initialIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
for (int i = 0; i < widget.titles.length; i++)
Expanded(
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () => setState(() => _selectedIndex = i),
child: Container(
color: Colors.transparent,
child: Column(
children: [
const SizedBox(
height: 16,
),
AnimatedCrossFade(
firstChild: Text(
widget.titles[i],
style:
STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
secondChild: Text(
widget.titles[i],
style:
STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
crossFadeState: _selectedIndex == i
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 250),
),
2023-04-11 14:28:05 +00:00
const SizedBox(
height: 19,
),
],
),
),
),
),
),
],
),
Stack(
children: [
Container(
height: 2,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
),
),
AnimatedSlide(
offset: Offset(_selectedIndex.toDouble(), 0),
duration: duration,
child: Container(
height: 2,
width: constraints.maxWidth / widget.titles.length,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
),
],
),
AnimatedSwitcher(
duration: duration,
transitionBuilder: (child, animation) {
return FadeTransition(
opacity: animation,
child: child,
);
},
layoutBuilder: (currentChild, prevChildren) {
return Stack(
alignment: Alignment.topCenter,
children: [
...prevChildren,
if (currentChild != null) currentChild,
],
);
},
child: AnimatedAlign(
2023-04-11 14:28:05 +00:00
key: Key("${widget.titles[_selectedIndex]}_customTabKey"),
alignment: Alignment.topCenter,
duration: duration,
child: Padding(
padding: widget.childPadding ?? EdgeInsets.zero,
child: widget.children[_selectedIndex],
),
),
),
],
),
);
}
}