Files
huangguo_android/lib/hj_page/main_page/main_tabbar.dart
T
2026-09-15 15:44:13 +07:00

151 lines
5.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hgdj/assets_tool/images.dart';
import 'package:hgdj/hj_page/main_page/provider/bottom_bar_provider.dart';
import 'package:hgdj/hj_page/pre_sale/pre_sale_provider.dart';
import 'package:hgdj/hj_utils/screen.dart';
import 'package:hgdj/tools_base/widget/net_image_widget.dart';
import 'package:provider/provider.dart';
import '../../../config/config.dart';
import '../../../tools_base/event_bus/event_bus_util.dart';
import '../../../tools_base/event_bus/events.dart';
import '../home/provider/home_update_marker_provider.dart';
import '../mine/home_mine_logic.dart';
import 'main_logic.dart';
/// 底部导航栏:按 logic.tabs 渲染各 tab,选中态随 logic.curPageIndex 刷新
class MainPageTabbar extends StatelessWidget {
const MainPageTabbar({super.key});
MainPageLogic get logic => Get.find<MainPageLogic>();
void _selectIndex(int index) {
final switchingToHome = index == 0 && logic.curPageIndex.value != 0;
logic.jumpToPage(index);
eventBus.emit(TabIndexChanged(index: index));
//首页
if (index == 0) {
PreSaleProvider().refreshConfig(); //刷新预售权益
// 从其它底栏切回主页时重拉「最新」等更新标记,避免长时间停留 App 内感知不到红点
if (switchingToHome) {
HomeUpdateMarkerProvider().loadData();
}
}
// 短视频播/停不用在这里管:切走后 IndexedStack 不再 paint 该页,其 RepaintBoundary 图层
// 从图层树摘除,VisibilityDetector 收到 detach 回调报可见度 0,播放器自行暂停。
// 动短视频页的 RepaintBoundary 前,务必回归「切到别的 tab 还有没有声音」
//我的:切到该 tab 时整体刷新(用户信息/钱包/消息/预售/分层配置)
if (index == logic.tabs.length - 1 && Get.isRegistered<MineMainLogic>()) {
Get.find<MineMainLogic>().onRefresh();
}
}
@override
Widget build(BuildContext context) {
//选中态与内容页同源 curPageIndex:底栏点击、deeplink 外部跳转都只改它一处
return Obx(() {
final cur = logic.curPageIndex.value;
return Container(
padding: EdgeInsets.fromLTRB(12, 0, 12, screen.paddingBottom),
decoration: BoxDecoration(
color: Colors.black,
border: Border(
top: BorderSide(color: Colors.black.withValues(alpha: 0.02))),
),
child: Row(
children: List.generate(logic.tabs.length, (index) {
if (index == 0)
return _scrollTopItem<HomeBottomProvider>(index, cur);
if (Config.darkWebEnable && index == 2)
return _scrollTopItem<DarkwebBottomProvider>(index, cur);
if (index == logic.communityTab)
return _scrollTopItem<CommunityBottomProvider>(index, cur);
return _normalItem(index, cur);
}),
),
);
});
}
/// 选中后再点会变「回到顶部」的 tab(主页/暗网/社区)
Widget _scrollTopItem<T extends BaseBottomProvider>(int index, int cur) {
final isSelected = index == cur;
return Consumer<T>(builder: (_, provider, __) {
final isTop = provider.showTop && isSelected;
final imagePath =
isTop ? 'jump_to_top.png'.homePath : _iconPath(index, isSelected);
//暗网配置Icon
final isDarkConfigImg = index == 2 &&
isSelected &&
Config.darkWebEnable &&
Config.darkWebIcon?.isNotEmpty == true;
return Expanded(
child: InkWell(
enableFeedback: false,
onTap: () => isTop ? provider.scrollToTop() : _selectIndex(index),
child: _tabContent(
isSelected: isSelected,
text: isTop ? '顶部' : logic.tabs[index].title,
icon: isDarkConfigImg
? NetworkImageLoader(
key: const ValueKey('darkIcon'),
imageUrl: Config.darkWebIcon)
: Image.asset(imagePath, key: ValueKey(imagePath), width: 24),
),
),
);
});
}
/// 普通 tab
Widget _normalItem(int index, int cur) {
final isSelected = index == cur;
final imagePath = _iconPath(index, isSelected);
return Expanded(
child: InkWell(
enableFeedback: false,
onTap: () => _selectIndex(index),
child: _tabContent(
isSelected: isSelected,
text: logic.tabs[index].title,
icon: Image.asset(imagePath, key: ValueKey(imagePath), width: 24),
),
),
);
}
String _iconPath(int index, bool isSelected) =>
isSelected ? logic.tabs[index].imageSel : logic.tabs[index].imageNor;
/// 图标 + 文案:图标切换(key 变即图片路径变)交叉淡入,文字颜色平滑过渡
Widget _tabContent(
{required Widget icon, required bool isSelected, required String text}) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 24,
alignment: Alignment.center,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 180), child: icon),
),
2.sizeBoxH,
AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: TextStyle(
color: isSelected
? const Color(0xffF68804)
: const Color(0xff656565),
fontSize: 10,
),
child: Text(text),
),
],
),
);
}
}