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

ChangeNotifierProvider无法更新监听器,Flutter代码问题求助

Flutter中ChangeNotifierProvider无法同步滚动偏移量到UI的问题

我将实际Flutter项目简化为以下代码,希望通过ChangeNotifierProvider让ListView的滚动偏移量同步显示在底部的Text组件中。滚动时控制台能打印出偏移量,但Text组件始终不更新,请问问题出在哪里?

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ViewController extends StatefulWidget {
  const ViewController({super.key});

  @override
  State<ViewController> createState() => _ViewControllerState();
}

class _ViewControllerState extends State<ViewController> {
  final scrollController = ScrollController();
  final scrollProvider = ScrollProvider();

  @override
  void initState() {
    scrollController.addListener(scrollHandler);
    super.initState();
  }

  @override
  void dispose() {
    scrollController.removeListener(scrollHandler);
    super.dispose();
  }

  void scrollHandler() {
    scrollProvider.setCurrentOffset(scrollController.offset);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        ListView.builder(
          controller: scrollController,
          itemBuilder: ((context, index) {
            return Text(
              "Index: $index",
              style: const TextStyle(fontSize: 40),
            );
          }),
          itemCount: 100,
        ),
        Positioned(
          left: 0,
          bottom: 0,
          right: 0,
          child: CupertinoButton(
            onPressed: (() {}),
            child: ChangeNotifierProvider(
              create: ((_) => scrollProvider),
              child: Text(
                "Offset: ${scrollProvider.currentOffset}",
                style: const TextStyle(
                  fontSize: 32,
                  fontWeight: FontWeight.bold,
                  backgroundColor: Colors.black,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

class ScrollProvider extends ChangeNotifier {
  double? currentOffset;
  void setCurrentOffset(valueToSet) {
    if (currentOffset != valueToSet) {
      currentOffset = valueToSet;
      print("currentOffset: $currentOffset");
      notifyListeners();
    }
  }
}

问题根源

  1. 直接访问Provider实例变量,未订阅变化:Text组件直接使用scrollProvider.currentOffset获取值,这种方式不会监听notifyListeners()的通知——即使Provider中的偏移量更新,Text也不会触发重建。
  2. ChangeNotifierProvider使用不规范:
    • create方法应当返回新实例,复用已存在的scrollProvider虽不会直接报错,但更规范的做法是用ChangeNotifierProvider.value传递已有实例;
    • Provider嵌套层级过深,且核心的Text组件没有通过Provider的监听机制获取数据,导致无法感知变化。

修复方案

有两种常用方式实现UI同步更新:

方式一:使用Consumer组件

Consumer会自动订阅Provider的变化,当notifyListeners()调用时,其builder方法会重新执行,更新UI:

@override
Widget build(BuildContext context) {
  // 将Provider提升到外层,让所有子Widget都能访问
  return ChangeNotifierProvider.value(
    value: scrollProvider,
    child: Stack(
      children: [
        ListView.builder(
          controller: scrollController,
          itemBuilder: ((context, index) {
            return Text(
              "Index: $index",
              style: const TextStyle(fontSize: 40),
            );
          }),
          itemCount: 100,
        ),
        Positioned(
          left: 0,
          bottom: 0,
          right: 0,
          child: CupertinoButton(
            onPressed: () {},
            child: Consumer<ScrollProvider>(
              builder: (context, provider, child) {
                return Text(
                  "Offset: ${provider.currentOffset ?? 0.0}",
                  style: const TextStyle(
                    fontSize: 32,
                    fontWeight: FontWeight.bold,
                    backgroundColor: Colors.black,
                  ),
                );
              },
            ),
          ),
        ),
      ],
    ),
  );
}

方式二:使用Provider.of<ScrollProvider>(context)

通过Provider.of获取实例并开启监听(默认listen: true),当Provider变化时,当前Widget会重建:

// 替换原Text所在部分
child: Text(
  "Offset: ${Provider.of<ScrollProvider>(context).currentOffset ?? 0.0}",
  style: const TextStyle(
    fontSize: 32,
    fontWeight: FontWeight.bold,
    backgroundColor: Colors.black,
  ),
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:50:28