df_tab_bar.dart 4.39 KB
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';

class DfTabBar extends StatelessWidget {
  final int selectedIndex;
  final ValueChanged<int> onTap;

  const DfTabBar({
    super.key,
    required this.selectedIndex,
    required this.onTap,
  });

  static const _selectedBgColor = Color(0xFFF3F3F3);

  static const _tabIcons = [
    'assets/images/tabbar/icon_today.png',
    'assets/images/tabbar/icon_trend.png',
    'assets/images/tabbar/icon_friends.png',
    'assets/images/tabbar/icon_my.png',
  ];

  static const _selectedTabIcons = [
    'assets/images/tabbar/icon_today_selected.png',
    'assets/images/tabbar/icon_trend_selected.png',
    'assets/images/tabbar/icon_friends_selected.png',
    'assets/images/tabbar/icon_my_selected.png',
  ];

  @override
  Widget build(BuildContext context) {
    final l10n = context.l10n;
    final tabLabels = [
      l10n.tabToday,
      l10n.tabTrend,
      l10n.tabFriends,
      l10n.tabMy,
    ];

    return SafeArea(
      top: false,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
        child: Container(
          height: 56,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(28),
            boxShadow: const [
              BoxShadow(
                color: Color(0x33000000), // rgba(0,0,0,0.2)
                blurRadius: 24,
                offset: Offset(0, 6),
              ),
            ],
          ),
          child: Padding(
            padding: const EdgeInsets.all(4),
            child: LayoutBuilder(
              builder: (context, constraints) {
                final tabWidth = constraints.maxWidth / _tabIcons.length;
                return Stack(
                  clipBehavior: Clip.none,
                  children: [
                    AnimatedPositioned(
                      duration: const Duration(milliseconds: 200),
                      curve: Curves.easeInOut,
                      left: selectedIndex * tabWidth,
                      top: 0,
                      bottom: 0,
                      width: tabWidth,
                      child: const DecoratedBox(
                        decoration: BoxDecoration(
                          color: _selectedBgColor,
                          borderRadius: BorderRadius.all(Radius.circular(24)),
                        ),
                      ),
                    ),
                    Row(
                      children: List.generate(_tabIcons.length, (i) {
                        final isSelected = selectedIndex == i;
                        return Expanded(
                          child: RepaintBoundary(
                            child: GestureDetector(
                              onTap: () => onTap(i),
                              behavior: HitTestBehavior.opaque,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Image.asset(
                                    isSelected
                                        ? _selectedTabIcons[i]
                                        : _tabIcons[i],
                                    width: 24,
                                    height: 24,
                                    gaplessPlayback: true,
                                  ),
                                  const SizedBox(height: 2),
                                  Text(
                                    tabLabels[i],
                                    style: TextStyle(
                                      fontSize: 9,
                                      fontWeight: FontWeight.w500,
                                      color: isSelected
                                          ? context.colors.primary
                                          : context.colors.textSecondary,
                                      height: 1.4,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        );
                      }),
                    ),
                  ],
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}