110 lines
3.0 KiB
Dart
Executable File
110 lines
3.0 KiB
Dart
Executable File
import 'package:flutter/material.dart';
|
||
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
||
|
||
/// 用来描述底部导航栏的每一项
|
||
class KRCustomBottomNavBarItem {
|
||
/// 未选中时的图片名称
|
||
final String imageName;
|
||
|
||
/// 选中时的图片名称(可选,不传则用同一张 imageName)
|
||
final String? activeImageName;
|
||
|
||
/// 标签(可选)
|
||
final String? label;
|
||
|
||
KRCustomBottomNavBarItem({
|
||
required this.imageName,
|
||
this.activeImageName,
|
||
this.label,
|
||
});
|
||
}
|
||
|
||
class KRCustomBottomNavBar extends StatelessWidget {
|
||
/// 传入当前选中的索引
|
||
final int currentIndex;
|
||
|
||
/// 导航栏的各个条目信息
|
||
final List<KRCustomBottomNavBarItem> items;
|
||
|
||
/// 点击某项时的回调
|
||
final ValueChanged<int> onTap;
|
||
|
||
/// 背景色
|
||
final Color backgroundColor;
|
||
|
||
/// 选中时 图标/文字 颜色
|
||
final Color selectedColor;
|
||
|
||
/// 未选中时 图标/文字 颜色
|
||
final Color unselectedColor;
|
||
|
||
/// 导航栏高度(不含安全区额外高度)
|
||
final double height;
|
||
|
||
/// 是否在内部自动使用 SafeArea
|
||
final bool useSafeArea;
|
||
|
||
const KRCustomBottomNavBar({
|
||
Key? key,
|
||
required this.currentIndex,
|
||
required this.items,
|
||
required this.onTap,
|
||
this.backgroundColor = Colors.white,
|
||
this.selectedColor = Colors.blue,
|
||
this.unselectedColor = Colors.grey,
|
||
this.height = 56.0,
|
||
this.useSafeArea = true,
|
||
}) : super(key: key);
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
assert(items.isNotEmpty, 'The items list cannot be empty.');
|
||
assert(currentIndex >= 0 && currentIndex < items.length,
|
||
'The currentIndex must be within the bounds of the items list.');
|
||
|
||
Widget child = Container(
|
||
color: backgroundColor,
|
||
height: height,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||
children: List.generate(items.length, (index) {
|
||
final item = items[index];
|
||
final bool isSelected = (index == currentIndex);
|
||
|
||
final iconName = isSelected
|
||
? (item.activeImageName ?? item.imageName)
|
||
: item.imageName;
|
||
|
||
final textColor = isSelected ? selectedColor : unselectedColor;
|
||
|
||
return Expanded(
|
||
child: InkWell(
|
||
onTap: () => onTap(index),
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
KrLocalImage(
|
||
imageName: iconName,
|
||
height: 24,
|
||
width: 24,
|
||
),
|
||
if (item.label != null) ...[
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
item.label!,
|
||
style: TextStyle(color: textColor, fontSize: 12),
|
||
),
|
||
],
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}),
|
||
),
|
||
);
|
||
|
||
// 使用 SafeArea 包裹,避免底部被手势栏遮挡
|
||
return useSafeArea ? SafeArea(child: child) : child;
|
||
}
|
||
}
|