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

Flutter ListView Builder真机无法显示,模拟器正常问题求助

Flutter真机聊天列表空白问题排查与解决方案

问题背景

使用ListView.builder实现聊天列表,Android/iOS模拟器运行正常,但发布测试后真机上ListView区域空白。其他页面采用相同格式的ListView(仅数据和样式不同)可正常显示。

相关代码

聊天列表核心代码

Expanded(
  child: ListView.builder(
    controller: _controller,
    itemCount: listChat.length,
    itemBuilder: (context, index) {
      return Padding(
        padding: EdgeInsets.only(
            left: 15,
            right: 15,
            top: index == 0 ? 10 : 0,
            bottom: 10),
        child: listChat.isEmpty
            ? Container(
                alignment: Alignment.center,
                child: Chip(
                  backgroundColor: Colors.grey[200],
                  side: const BorderSide(
                      color: Color.fromARGB(255, 239, 239, 239)),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(100)),
                  label: TextComp(
                      text: "Tidak ada chat",
                      fontSize: 14,
                      color: Colors.grey,
                      fontWeight: FontWeight.bold,
                      textAlign: TextAlign.left),
                ),
              )
            : listChat[index]['jenis'] == "join"
                ? Container(
                    alignment: Alignment.center,
                    child: Chip(
                      backgroundColor: Colors.grey[200],
                      side: const BorderSide(
                          color: Color.fromARGB(255, 239, 239, 239)),
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(100)),
                      label: TextComp(
                          text: listChat[index]['nama'] == null
                              ? "Seseorang telah bergabung"
                              : listChat[index]['nama'] +
                                  " telah bergabung",
                          fontSize: 14,
                          color: Colors.grey,
                          fontWeight: FontWeight.bold,
                          textAlign: TextAlign.left),
                    ),
                  )
                : Row(
                    children: [
                      Expanded(
                        child: Column(
                          crossAxisAlignment: listChat[index]['id_user'] == idUser
                              ? CrossAxisAlignment.end
                              : CrossAxisAlignment.start,
                          children: [
                            Container(
                              child: TextComp(
                                  text: listChat[index]['nama'] == null
                                      ? "Seseorang"
                                      : listChat[index]['nama'],
                                  fontSize: 14,
                                  color: Colors.black,
                                  fontWeight: FontWeight.bold,
                                  textAlign: TextAlign.left),
                            ),
                            listChat[index]['jenis'] == "Materi"
                                ? Container(
                                    margin: const EdgeInsets.only(top: 0),
                                    child: Chip(
                                      backgroundColor: Colors.grey[200],
                                      side: const BorderSide(color: Colors.teal),
                                      shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.circular(100)),
                                      label: TextComp(
                                          text: listChat[index]['judul'] == null
                                              ? ""
                                              : listChat[index]['judul'],
                                          fontSize: 10,
                                          color: Colors.teal,
                                          fontWeight: FontWeight.bold,
                                          textAlign: TextAlign.left),
                                    ),
                                  )
                                : Container(),
                            ChipChat(
                                onTap: () {},
                                text: listChat[index]['isi_chat'] == null
                                    ? ""
                                    : listChat[index]['isi_chat'],
                                jenis: listChat[index]['jenis'],
                                choosen: true),
                            Container(
                              child: TextComp(
                                  text: Moment(DateTime.parse(listChat[index]['timestamp']).toLocal())
                                      .format('LLL'),
                                  fontSize: 12,
                                  color: Colors.grey,
                                  fontWeight: FontWeight.normal,
                                  textAlign: TextAlign.left),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
      );
    },
  ),
),

ChipChat组件代码

import 'package:flutter/material.dart';
import 'package:kambiumgo/components/text.dart';

class ChipChat extends StatelessWidget {
  Function onTap;
  String text;
  String jenis;
  bool choosen;
  ChipChat(
      {super.key,
      required this.onTap,
      required this.text,
      required this.jenis,
      required this.choosen});

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(right: 0),
      child: GestureDetector(
        onTap: () {
          onTap();
        },
        child: Container(
          constraints: BoxConstraints(
              minWidth: 0, maxWidth: MediaQuery.of(context).size.width * 0.8),
          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            border: Border.all(
              color: choosen
                  ? jenis == "Materi"
                      ? Colors.blueAccent
                      : Colors.teal
                  : const Color.fromARGB(255, 239, 239, 239),
            ),
            color: choosen
                ? jenis == "Materi"
                    ? Colors.blueAccent
                    : Colors.teal
                : const Color.fromARGB(255, 239, 239, 239),
          ),
          child: Wrap(
            children: [
              TextComp(
                text: text,
                fontSize: 14,
                color: choosen ? Colors.white : Colors.black,
                fontWeight: FontWeight.bold,
                textAlign: TextAlign.left,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

排查方向与解决方案

1. 空列表逻辑错误(核心问题)

原代码中itemCount: listChat.length,当listChat为空时,itemCount为0,itemBuilder不会执行,导致空状态的Container永远无法渲染,真机上若数据未加载成功则直接空白。

修复方案:将空列表判断移到ListView.builder外部:

Expanded(
  child: listChat.isEmpty
      ? Container(
          alignment: Alignment.center,
          child: Chip(
            backgroundColor: Colors.grey[200],
            side: const BorderSide(color: Color.fromARGB(255, 239, 239, 239)),
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(100)),
            label: TextComp(
                text: "Tidak ada chat",
                fontSize: 14,
                color: Colors.grey,
                fontWeight: FontWeight.bold,
                textAlign: TextAlign.left),
          ),
        )
      : ListView.builder(
          controller: _controller,
          itemCount: listChat.length,
          itemBuilder: (context, index) {
            // 原itemBuilder逻辑(去掉listChat.isEmpty判断)
          },
        ),
)

2. DateTime.parse的异常风险

发布模式下,若timestamp格式不符合预期,DateTime.parse会抛出异常导致UI渲染失败,模拟器可能因测试数据格式规范未暴露问题。

修复方案:添加异常捕获,或确保时间格式兼容:

// 替换原时间格式化代码
String formatTimestamp(String timestamp) {
  try {
    final date = DateTime.parse(timestamp).toLocal();
    // 改用intl包的DateFormat替代moment库,避免第三方库兼容问题
    return DateFormat('LLL').format(date);
  } catch (e) {
    return ""; // 或默认提示文本
  }
}

3. 第三方库兼容问题

Moment库在发布模式下可能存在优化或兼容性问题,建议替换为Flutter官方推荐的intl包处理时间格式化。

步骤:

  • 添加依赖:pubspec.yaml中加入intl: ^0.18.1
  • 导入:import 'package:intl/intl.dart';
  • 使用DateFormat替代Moment

4. 组件类型与渲染问题

  • ChipChat中的onTap参数类型为Function,建议改为VoidCallback以避免类型不匹配:
    VoidCallback onTap; // 替换原Function类型
    
  • 检查TextComp组件在发布模式下的渲染逻辑,确保字体、样式无异常,可临时替换为原生Text组件测试是否恢复显示。

内容的提问来源于stack exchange,提问作者Haksatrya Bhaswara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:40:06