You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现图片堆叠组件并添加总用户数显示功能

需求:实现带总用户数的堆叠头像组件

我参考视频实现了图片堆叠效果,但还不满足需求——需要在这个堆叠结构基础上显示总用户数(类似带“+X”的圆形标识样式)。Pub上的相关包都不符合要求,求帮忙。


现有堆叠组件代码

import 'package:flutter/material.dart';

class StackedWidgets extends StatelessWidget {
  final List<Widget> items;
  final TextDirection direction;
  final double size;
  final double xShift;

  const StackedWidgets({
    Key? key,
    required this.items,
    this.direction = TextDirection.ltr,
    this.size = 100,
    this.xShift = 20,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final allItems = items
        .asMap()
        .map((index, item) {
          final left = size - xShift;

          final value = Container(
            width: size,
            height: size,
            child: item,
            margin: EdgeInsets.only(left: left * index),
          );

          return MapEntry(index, value);
        })
        .values
        .toList();

    return Stack(
      children: direction == TextDirection.ltr
          ? allItems.reversed.toList()
          : allItems,
    );
  }
}

组件使用代码

Widget buildStackedImages({
  TextDirection direction = TextDirection.ltr,
}) {
  final double size = 100;
  final double xShift = 20;
  final urlImages = [
    'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=633&q=80',
    'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80',
    'https://images.unsplash.com/photo-1616766098956-c81f12114571?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80',
  ];

  final items = urlImages.map((urlImage) => buildImage(urlImage)).toList();

  return StackedWidgets(
    direction: direction,
    items: items,
    size: size,
    xShift: xShift,
  );
}

Widget buildImage(String urlImage) {
  final double borderSize = 5;

  return ClipOval(
    child: Container(
      padding: EdgeInsets.all(borderSize),
      color: Colors.white,
      child: ClipOval(
        child: Image.network(
          urlImage,
          fit: BoxFit.cover,
        ),
      ),
    ),
  );
}

解决方案

修改StackedWidgets组件,新增总用户数参数,当总数量超过显示的头像数时,自动添加显示剩余数量的圆形组件:

修改后的StackedWidgets组件

import 'package:flutter/material.dart';

class StackedWidgets extends StatelessWidget {
  final List<Widget> items;
  final int totalCount; // 总用户数
  final TextDirection direction;
  final double size;
  final double xShift;
  final int displayCount; // 最多显示的头像数量

  const StackedWidgets({
    Key? key,
    required this.items,
    required this.totalCount,
    this.direction = TextDirection.ltr,
    this.size = 100,
    this.xShift = 20,
    this.displayCount = 3,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Widget> displayItems = [];
    // 确定要显示的头像数量
    int showItemCount = items.length > displayCount ? displayCount : items.length;
    displayItems.addAll(items.take(showItemCount));

    // 总数量超过显示数时,添加剩余数量组件
    if (totalCount > showItemCount) {
      displayItems.add(_buildRemainingCountWidget(totalCount - showItemCount));
    }

    final allItems = displayItems
        .asMap()
        .map((index, item) {
          final left = size - xShift;
          final value = Container(
            width: size,
            height: size,
            child: item,
            margin: EdgeInsets.only(left: left * index),
          );
          return MapEntry(index, value);
        })
        .values
        .toList();

    return Stack(
      children: direction == TextDirection.ltr
          ? allItems.reversed.toList()
          : allItems,
    );
  }

  // 构建剩余数量显示组件
  Widget _buildRemainingCountWidget(int count) {
    return ClipOval(
      child: Container(
        width: size,
        height: size,
        color: Colors.grey[300],
        child: Center(
          child: Text(
            "+$count",
            style: TextStyle(
              fontSize: size * 0.4,
              fontWeight: FontWeight.bold,
              color: Colors.black87,
            ),
          ),
        ),
      ),
    );
  }
}

修改后的使用代码

Widget buildStackedImages({
  TextDirection direction = TextDirection.ltr,
}) {
  final double size = 100;
  final double xShift = 20;
  final urlImages = [
    'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=633&q=80',
    'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80',
    'https://images.unsplash.com/photo-1616766098956-c81f12114571?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80',
  ];
  final totalUsers = 10; // 设置总用户数

  final items = urlImages.map((urlImage) => buildImage(urlImage)).toList();

  return StackedWidgets(
    direction: direction,
    items: items,
    totalCount: totalUsers,
    size: size,
    xShift: xShift,
    displayCount: 3, // 控制显示3个头像,剩余数量显示+7
  );
}

Widget buildImage(String urlImage) {
  final double borderSize = 5;

  return ClipOval(
    child: Container(
      padding: EdgeInsets.all(borderSize),
      color: Colors.white,
      child: ClipOval(
        child: Image.network(
          urlImage,
          fit: BoxFit.cover,
        ),
      ),
    ),
  );
}

说明

  • 通过totalCount传入总用户数,displayCount控制最多显示的头像数量
  • 当总用户数超过显示数时,自动追加带“+X”的圆形组件
  • 可根据需求修改剩余数量组件的背景色、字体样式等

内容的提问来源于stack exchange,提问作者Abdullah T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:05:11