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

Flutter中为ListView添加无限滚动的实现求助

Flutter ListView 无限滚动实现方案

结合你提供的API方法和评论组件,以下是实现无限滚动的具体步骤:

1. 页面状态变量定义

在使用showComment的页面State类中,添加以下变量用于分页控制:

late ScrollController _scrollController;
int _currentPage = 1; // 当前页码,初始为1
bool _isLoading = false; // 是否正在加载数据
bool _hasMore = true; // 是否还有更多数据可加载
List<RestaurantReview> _reviews = []; // 存储所有评论数据

2. 初始化滚动控制器与监听

在initState中初始化滚动控制器,并添加滚动到底部的监听逻辑:

@override
void initState() {
  super.initState();
  _scrollController = ScrollController()
    ..addListener(() {
      // 当滚动到底部、还有更多数据且未在加载时,触发加载更多
      if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent && _hasMore && !_isLoading) {
        _loadMoreReviews();
      }
    });
  // 加载第一页初始数据
  _loadInitialReviews();
}

@override
void dispose() {
  // 页面销毁时释放控制器
  _scrollController.dispose();
  super.dispose();
}

3. 实现数据加载方法

编写初始加载和加载更多的方法,调用你的API并处理数据追加:

// 加载第一页数据
Future<void> _loadInitialReviews() async {
  _isLoading = true;
  setState(() {});
  
  try {
    // 替换成你的restaurantId实际值
    final newReviews = await yourViewModel.filterReview(restaurantId, page: _currentPage);
    _reviews.addAll(newReviews);
    // 如果返回数据为空,标记无更多数据
    if (newReviews.isEmpty) {
      _hasMore = false;
    }
  } catch (e) {
    // 处理加载错误,比如显示提示
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('加载评论失败:$e'))
    );
  } finally {
    _isLoading = false;
    setState(() {});
  }
}

// 加载更多数据
Future<void> _loadMoreReviews() async {
  if (_isLoading || !_hasMore) return;
  
  _isLoading = true;
  _currentPage += 1;
  setState(() {});
  
  try {
    final newReviews = await yourViewModel.filterReview(restaurantId, page: _currentPage);
    if (newReviews.isNotEmpty) {
      _reviews.addAll(newReviews);
    } else {
      _hasMore = false;
    }
  } catch (e) {
    // 加载失败时回退页码
    _currentPage -= 1;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('加载更多失败:$e'))
    );
  } finally {
    _isLoading = false;
    setState(() {});
  }
}

4. 修改评论列表组件

调整showComment方法,整合分页逻辑与加载状态:

Widget showComment(BuildContext context) {
  return SizedBox(
    child: ListView.builder(
      controller: _scrollController, // 绑定滚动控制器
      // 加载中时多显示一个加载指示器item
      itemCount: _reviews.length + (_isLoading ? 1 : 0),
      shrinkWrap: true,
      itemBuilder: (BuildContext context, int index) {
        // 最后一个item且加载中时,显示加载指示器
        if (index == _reviews.length) {
          return Padding(
            padding: EdgeInsets.symmetric(vertical: 16.h),
            child: Center(child: CircularProgressIndicator()),
          );
        }
        
        final review = _reviews[index];
        return Container(
          margin: EdgeInsets.only(top: 10.h),
          padding: EdgeInsets.all(10.h),
          width: MediaQuery.of(context).size.width,
          height: 80.h,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(10),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  Text(
                    "${review.userFullName}",
                    style: TextStyle(
                      fontSize: 12.h,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Spacer(),
                  RatingBar(
                    ignoreGestures: true,
                    initialRating: review.rating,
                    allowHalfRating: false,
                    direction: Axis.horizontal,
                    itemCount: 5,
                    itemSize: 15,
                    ratingWidget: RatingWidget(
                      full: Icon(Icons.star_rounded, color: Colors.yellow),
                      half: Icon(Icons.star_half_rounded, color: Colors.yellow),
                      empty: Icon(Icons.star_border_rounded, color: Colors.black),
                    ),
                    onRatingUpdate: (rating) {}, // 只读状态无需处理
                  ),
                ],
              ),
              SizedBox(height: 4.h),
              Text(
                DateFormat('dd/MM/yyyy').format(review.createdDate),
                style: TextStyle(fontSize: 8.h, color: Colors.grey),
              ),
              SizedBox(height: 10.h),
              Text(
                "${review.comment ?? ''}",
                style: TextStyle(
                  fontSize: 10.h,
                ),
              ),
            ],
          ),
        );
      },
    ),
  );
}

注意事项

  • 确保你的API支持分页:当前API使用page参数,需要后端正确返回对应页码的数据。
  • 避免重复请求:通过_isLoading状态防止滚动时多次触发加载。
  • 错误处理:加载失败时回退页码,避免页码错乱。
  • ViewModel数据处理:原API方法会替换reviewList,这里我们直接使用API返回的新数据追加到页面本地列表,避免ViewModel数据被覆盖影响其他逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:53:09