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

Flutter无限滚动组件报错:Null不是String的子类型类型转换错误

问题修复方案

1. 类型转换错误(_CastError)的解决

错误根源是你在ListTile的subtitle中尝试获取_posts[index]['body']并强制转为String,但所有测试数据里根本没有'body'这个键,对应的文本字段实际是'intro-text'。访问不存在的键会得到null,强制转换就会触发类型错误。

修复方法:将subtitle的取值改为'intro-text',同时增加空安全处理避免后续问题:

subtitle: Text(_posts[index]['intro-text'] as String? ?? '暂无简介'),

2. Future.delayed未生效的解决

你直接调用Future.delayed(Duration(seconds: 300));但未使用await,且start函数不是异步函数,导致延迟操作不会阻塞后续代码,setState会立刻执行,因此不需要等待5分钟就隐藏了加载指示器。

修复方法:将start改为异步函数,用await等待延迟完成:

Future<void> start() async {
  _posts = [
    // 测试数据保持不变
  ];
  await Future.delayed(const Duration(seconds: 300));

  setState(() {
    _isFirstLoadRunning = false;
  });
}

额外优化:明确变量类型提升安全性

目前_posts是var类型,建议明确为List<Map<String, dynamic>>,提升代码可读性和类型安全性:

List<Map<String, dynamic>> _posts = [];

修复后的完整代码

class NewsFeed extends Stateful Widget {
  @override
  GetNews createState() => GetNews();
}

class GetNews extends State<NewsFeed> {
  List<Map<String, dynamic>> _posts = [];

  bool _hasNextPage = true;
  bool _isFirstLoadRunning = false;
  bool _isLoadMoreRunning = false;

  void _loadMore() async {
    if (_hasNextPage == true &&
        _isLoadMoreRunning == false &&
        _controller.position.extentAfter < 300) {
      setState(() {
        _isLoadMoreRunning = true;
      });

      try {
        var res = [
          {
            'title': 'Skull Crushers vs. Tricep Pulldown',
            'by': 'someone',
            'intro-text':
                'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus est pellentesque elit ullamcorper dignissim. Pharetra convallis posuere morbi leo urna. Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ornare arcu dui vivamus arcu felis bibendum. Arcu felis bibendum ut tristique et.',
            'image':
                'https://media.self.com/photos/6398b36c72eb56f726777d06/4:3/w_2560%2Cc_limit/weekly-workout-schedule.jpeg'
          },
          {
            'title': 'Skull Crushers vs. Tricep Pulldown',
            'by': 'someone',
            'intro-text':
                'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus est pellentesque elit ullamcorper dignissim. Pharetra convallis posuere morbi leo urna. Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ornare arcu dui vivamus arcu felis bibendum. Arcu felis bibendum ut tristique et.',
            'image':
                'https://media.self.com/photos/6398b36c72eb56f726777d06/4:3/w_2560%2Cc_limit/weekly-workout-schedule.jpeg'
          }
        ];
        if (res.isNotEmpty) {
          setState(() {
            _posts.addAll(res);
          });
        } else {
          setState(() {
            _hasNextPage = false;
          });
        }
      } catch (err) {
        print('Something went wrong!');
      }

      setState(() {
        _isLoadMoreRunning = false;
      });
    }
  }

  Future<void> start() async {
    _posts = [
      {
        'title': 'Skull Crushers vs. Tricep Pulldown',
        'by': 'someone',
        'intro-text':
            'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus est pellentesque elit ullamcorper dignissim. Pharetra convallis posuere morbi leo urna. Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ornare arcu dui vivamus arcu felis bibendum. Arcu felis bibendum ut tristique et.',
            'image':
                'https://media.self.com/photos/6398b36c72eb56f726777d06/4:3/w_2560%2Cc_limit/weekly-workout-schedule.jpeg'
      },
      {
        'title': 'Skull Crushers vs. Tricep Pulldown',
        'by': 'someone',
        'intro-text':
            'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus est pellentesque elit ullamcorper dignissim. Pharetra convallis posuere morbi leo urna. Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ornare arcu dui vivamus arcu felis bibendum. Arcu felis bibendum ut tristique et.',
            'image':
                'https://media.self.com/photos/6398b36c72eb56f726777d06/4:3/w_2560%2Cc_limit/weekly-workout-schedule.jpeg'
      }
    ];
    await Future.delayed(const Duration(seconds: 300));

    setState(() {
      _isFirstLoadRunning = false;
    });
  }

  late ScrollController _controller;
  @override
  void initState() {
    super.initState();
    _isFirstLoadRunning = true;
    start();
    _controller = ScrollController()..addListener(_loadMore);
  }

  @override
  Widget build(BuildContext context) {
    return _isFirstLoadRunning
        ? const Center(
            child: CircularProgressIndicator(),
          )
        : Column(
            children: [
              Expanded(
                child: ListView.builder(
                  itemCount: _posts.length,
                  controller: _controller,
                  itemBuilder: (_, index) => Card(
                    margin:
                        const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
                    child: ListTile(
                      title: Text(_posts[index]['title'] as String? ?? '暂无标题'),
                      subtitle: Text(_posts[index]['intro-text'] as String? ?? '暂无简介'),
                    ),
                  ),
                ),
              ),
              if (_isLoadMoreRunning == true)
                const Padding(
                  padding: EdgeInsets.only(top: 10, bottom: 40),
                  child: Center(
                    child: CircularProgressIndicator(),
                  ),
                ),
              if (_hasNextPage == false)
                Container(
                  padding: const EdgeInsets.only(top: 30, bottom: 40),
                  color: Colors.amber,
                  child: const Center(
                    child: Text('You have fetched all of the content'),
                  ),
                ),
            ],
          );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 15:15:01