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

Firebase媒体展示异常:已上传的图片视频无法在ListView显示

问题分析与修复方案

核心问题定位

从代码中可以看出,导致「无照片存在」的主要原因包括状态处理不完整、硬编码的列表长度、媒体类型未区分,以及UI反馈缺失,具体如下:


代码修复点

1. 修复展示页面的状态逻辑(BlocBuilder部分)

BlocBuilder<ReachedUploadCubit, ReachedUploadState>(
  builder: (context, state) {
    if (state is ImagePicked) {
      files = state.media;
      // 选中媒体后显示本地预览列表
      return SizedBox(
        height: 600,
        child: ListView.builder(
          itemCount: files.length,
          itemBuilder: (context, index) {
            final file = files[index];
            final isVideo = file.path.endsWith('.mp4') || file.path.endsWith('.mov');
            return ImageVideosWidget(
              mediaUrl: file.path,
              mediaPath: file.path,
              placeHolder: isVideo ? 'assets/video_placeholder.svg' : 'assets/image_placeholder.svg',
              onTap: () => context.read<ReachedUploadCubit>().removeMedia(index),
              isVideo: isVideo,
            );
          },
        ),
      );
    } else if (state is ImageUploadInProgress) {
      return const LinearProgressIndicator();
    } else if (state is ImageUploadFailure) {
      return Text(state.error);
    } else if (state is ImageUploadSuccess) {
      return SizedBox(
        height: 600,
        child: ListView.builder(
          // 替换硬编码的4,用实际上传的媒体数量
          itemCount: state.downloadUrl.length,
          itemBuilder: (context, index) {
            final isVideo = state.mediaTypes[index] == 'video';
            return ImageVideosWidget(
              mediaUrl: state.downloadUrl[index],
              mediaPath: state.downloadUrl[index],
              placeHolder: isVideo ? 'assets/video_placeholder.svg' : 'assets/image_placeholder.svg',
              onTap: () => context.read<ReachedUploadCubit>().deleteMedia(index),
              isVideo: isVideo,
            );
          },
        ),
      );
    } else if (state is ReachedUploadInitial) {
      return Stack(
        alignment: Alignment.center,
        children: [
          SvgPicture.asset('assets/rounded.svg'),
          InkWell(
              onTap: () async {
                await context.read<ReachedUploadCubit>().pickMedia();
                // 移除冗余的stream监听,BlocBuilder会自动响应状态变化
              },
              child: SvgPicture.asset('assets/imageUpload.svg')),
        ],
      );
    }
    // 明确显示无媒体的提示文本
    return const Center(child: Text('无照片存在'));
  },
)

2. 重构ImageVideosWidget(区分图片/视频展示)

class ImageVideosWidget extends StatelessWidget {
  final String mediaUrl;
  final String mediaPath;
  final String placeHolder;
  final Future<void> Function()? onTap;
  final bool isVideo;

  const ImageVideosWidget({
    Key? key,
    required this.mediaUrl,
    required this.mediaPath,
    required this.placeHolder,
    this.onTap,
    required this.isVideo,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      decoration: BoxDecoration(
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            spreadRadius: 5,
            blurRadius: 120,
            offset: const Offset(0, 10),
          ),
        ],
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 18),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            SvgPicture.asset(placeHolder),
            const SizedBox(width: 12),
            // 显示实际文件名而非固定文本
            Text(
              mediaPath.split('/').last,
              style: GoogleFonts.montserrat(
                fontSize: 13,
                fontWeight: FontWeight.w600,
                color: const Color(0xFF046AB2),
              ),
            ),
            const Spacer(),
            PopupMenuButton(
              itemBuilder: (BuildContext context) {
                return [
                  PopupMenuItem(
                    child: isArabic() ? const Text('عرض') : const Text('View'),
                    onTap: () {
                      WidgetsBinding.instance.addPostFrameCallback((_) {
                        showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return Dialog(
                              // 区分图片和视频的展示组件
                              child: isVideo 
                                  ? VideoPlayerWidget(videoUrl: mediaUrl)
                                  : PhotoViewWidget(imageUrl: mediaUrl),
                            );
                          },
                        );
                      });
                    },
                  ),
                  PopupMenuItem(
                    child: isArabic() ? const Text('حذف') : const Text('Delete'),
                    onTap: onTap,
                  ),
                ];
              },
            ),
          ],
        ),
      ),
    );
  }
}

额外注意事项

  • 确保ReachedUploadCubit的ImageUploadSuccess状态中,downloadUrl列表正确包含所有4个媒体的Firebase下载链接,新增mediaTypes字段标记每个媒体的类型(图片/视频)。
  • 检查Firebase存储的权限配置,确保应用拥有媒体文件的读取权限,避免下载链接无法访问。
  • 移除ImageVideosWidget中不必要的VideoPlayerCubit监听,仅在视频播放组件中保留相关状态管理。

内容的提问来源于stack exchange,提问作者Mahmoud Shaaban

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:54:49