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

Flutter开发:如何在ListView.separated中每4行插入一条广告

实现方案

直接调整列表的item计数逻辑,将广告作为独立item渲染,不要在separatorBuilder中处理广告,即可同时满足分隔线展示和每4条插广告的需求。

核心调整逻辑

  • 总item数计算:总长度 = 文章列表长度 + 广告位数量 + 1(底部加载占位),广告位数量公式为 (articleslist.length / 4).floor(),即每4篇文章插入1条广告
  • itemBuilder中做索引映射,判断当前位置需要渲染的内容类型
  • separatorBuilder保持默认返回Divider即可,所有item之间都会保留分隔线

修改后代码

ListView.separated(
  scrollDirection: Axis.vertical,
  shrinkWrap: true,
  controller: _scrollController,
  // 重新计算总item数:文章数 + 广告数 + 1个底部加载位
  itemCount: articleslist.length + (articleslist.length / 4).floor() + 1,
  itemBuilder: (BuildContext context, int index) {
    // 先处理底部加载位
    if (index == articleslist.length + (articleslist.length / 4).floor()) {
      _loading = true;
      return Center(
        child: Row(
          children: [
            Container(
              padding: EdgeInsets.all(5),
              child: CircularProgressIndicator(
                color: Colors.deepOrange[800],
              ),
            ),
            const SizedBox(width: 15),
            Text(
              'Articles are being loaded...',
              style: TextStyle(color: Colors.deepOrange[800]),
            )
          ],
        ),
      );
    }
    // 处理空列表
    if (articleslist.isEmpty) {
      return Container(
        child: Center(
          child: Text('Loading...',
              style: TextStyle(color: Colors.deepOrange))));
    }
    // 计算当前索引对应的内容类型
    int itemIndex = index - (index ~/ 5); // 每5个item里有1个广告,减去广告占用的索引位
    // 判断是否是广告位:索引+1能被5整除的位置就是广告位
    if ((index + 1) % 5 == 0) {
      // 这里替换为你自己的google_mobile_ads横幅广告实现
      return const BannerAdWidget();
    }
    // 剩余位置渲染文章内容
    var imgUrl = articleslist[itemIndex].img.toString();
    imgUrl = BaseUrl + imgUrl.toString();
    var title = articleslist[itemIndex].title;
    title = title.replaceAll(RegExp(r'<[^>]*>'), '');
    var body = articleslist[itemIndex].body;
    body = body.replaceAll(RegExp(r'<[^>]*>'), '');

    return InkWell(
      onTap: () {
        print('Tapped : ${articleslist[itemIndex].nid}');
        print(itemIndex);
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => DetailPage(
                  articleslist[itemIndex].title,
                  articleslist[itemIndex].img,
                  articleslist[itemIndex].nid,
                  articleslist[itemIndex].uid,
                  articleslist[itemIndex].created,
                )));
      },
      child: Container(
        padding: const EdgeInsets.fromLTRB(8.0, 6.0, 8.0, 0.0),
        child: Row(
          children: <Widget>[
            Container(
              width: 120,
              height: 75,
              child: ClipRRect(
                borderRadius: BorderRadius.circular(8),
                child: imgUrl == 'No img'
                    ? Image.asset('images/placeholder.png',
                    height: 220, fit: BoxFit.cover)
                    : FadeInImage.assetNetwork(
                  placeholder: 'images/placeholder.png',
                  image: imgUrl,
                  height: 220,
                  fit: BoxFit.cover,
                ),
              ),
            ),
            const SizedBox(width: 20),
            Expanded(
              child: Column(
                mainAxisAlignment:
                MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(
                    title,
                    style: const TextStyle(
                        color: Colors.black, fontSize: 16),
                  ),
                  const SizedBox(height: 10),
                  Text(
                    // 修正原代码未定义uid的问题
                    'author : ${articleslist[itemIndex].uid}',
                    style: const TextStyle(
                      fontSize: 10,
                    ),
                  ),
                  const SizedBox(height: 5),
                  Text(
                    articleslist[itemIndex].created,
                    style: const TextStyle(
                      fontSize: 10,
                    ),
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  },
  separatorBuilder: (context, index) => const Divider(),
),

补充说明

你只需要把代码中BannerAdWidget替换为你自己基于google_mobile_ads实现的横幅广告组件即可,原有的分隔线会保留在所有内容(文章、广告、加载位)之间,完全符合需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:36:04