如何在Flutter中实现带+号的有限dot_indicator(支持100+图片标识)
Flutter 实现带数量溢出提示的圆点指示器
核心思路
设定一个最大显示圆点数量(比如默认5个),根据总图片数量分两种情况处理:
- 当总数量 ≤ 最大显示数:正常渲染所有圆点,高亮当前选中的索引
- 当总数量 > 最大显示数:渲染前
最大显示数-1个圆点,最后一个位置显示+剩余数量的文本,同时处理选中索引超出可见范围时的高亮逻辑
完整代码实现
import 'package:flutter/material.dart'; class LimitedDotIndicator extends StatelessWidget { final int totalCount; final int currentIndex; final int maxVisibleDots; final Color selectedColor; final Color unselectedColor; final double dotSize; final double spacing; const LimitedDotIndicator({ super.key, required this.totalCount, required this.currentIndex, this.maxVisibleDots = 5, this.selectedColor = Colors.blue, this.unselectedColor = Colors.grey, this.dotSize = 10.0, this.spacing = 8.0, }); @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: _buildIndicatorChildren(), ); } List<Widget> _buildIndicatorChildren() { List<Widget> children = []; if (totalCount <= maxVisibleDots) { // 数量不多,显示所有圆点 for (int i = 0; i < totalCount; i++) { children.add( _buildDot(isSelected: i == currentIndex), ); if (i != totalCount - 1) { children.add(SizedBox(width: spacing)); } } } else { // 数量过多,显示部分圆点+剩余数量文本 final visibleDotCount = maxVisibleDots - 1; // 渲染前visibleDotCount个圆点 for (int i = 0; i < visibleDotCount; i++) { children.add( _buildDot(isSelected: i == currentIndex), ); children.add(SizedBox(width: spacing)); } // 渲染剩余数量提示文本 final remainingCount = totalCount - visibleDotCount; final isTextSelected = currentIndex >= visibleDotCount; children.add( Text( "+$remainingCount", style: TextStyle( color: isTextSelected ? selectedColor : unselectedColor, fontSize: dotSize * 1.2, fontWeight: isTextSelected ? FontWeight.bold : FontWeight.normal, ), ), ); } return children; } Widget _buildDot({required bool isSelected}) { return Container( width: dotSize, height: dotSize, decoration: BoxDecoration( color: isSelected ? selectedColor : unselectedColor, borderRadius: BorderRadius.circular(dotSize / 2), ), ); } } // 使用示例 class DemoPage extends StatefulWidget { const DemoPage({super.key}); @override State<DemoPage> createState() => _DemoPageState(); } class _DemoPageState extends State<DemoPage> { int currentIndex = 0; // 模拟100+的图片数量 final int totalImages = 120; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Dot Indicator Demo")), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 当前图片索引文本 Text("当前第 ${currentIndex + 1} 张图片"), const SizedBox(height: 20), // 使用自定义指示器 LimitedDotIndicator( totalCount: totalImages, currentIndex: currentIndex, maxVisibleDots: 5, ), const SizedBox(height: 20), // 切换按钮 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: currentIndex > 0 ? () => setState(() => currentIndex--) : null, child: const Text("上一张"), ), const SizedBox(width: 20), ElevatedButton( onPressed: currentIndex < totalImages - 1 ? () => setState(() => currentIndex++) : null, child: const Text("下一张"), ), ], ), ], ), ); } }
关键细节说明
- 可配置参数:你可以通过调整
maxVisibleDots来设置最多显示的圆点数量,还能自定义圆点颜色、大小、间距等样式 - 选中状态处理:当选中的索引超出了显示的圆点范围(比如第6张及以后,当maxVisibleDots=5时),剩余数量的文本会高亮,提示当前处于后面的图片组
- 布局适配:使用
mainAxisSize: MainAxisSize.min让指示器只占用必要的宽度,避免多余留白
内容的提问来源于stack exchange,提问作者Saurav Prakash
相关产品推荐
相关产品推荐

