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

Flutter WebView下拉刷新异常:触发后点击屏幕自动刷新

问题原因分析

你的问题核心出在自定义手势识别器的逻辑错误:

  • PlatformViewVerticalGestureRecognizer的handleEvent会响应所有指针事件(包括点击、滑动),只要WebView的滚动位置scrollY <5,就会触发刷新。首次下拉后页面回到顶部,后续点击时scrollY仍然小于5,所以每次点击都会触发reload()。
  • 同时外层ListView的_scrollListener也在监听滚动到顶部的事件,双重触发刷新逻辑,进一步加剧问题。
修复方案

1. 重构手势识别器,只响应下拉滑动动作

修改PlatformViewVerticalGestureRecognizer,仅当垂直下拉距离超过触摸阈值时才触发刷新,并且区分点击和滑动事件:

class PlatformViewVerticalGestureRecognizer extends VerticalDragGestureRecognizer {
  PlatformViewVerticalGestureRecognizer({PointerDeviceKind? kind}) : super(kind: kind);

  Offset _dragDistance = Offset.zero;
  // 标记是否已经触发过刷新,避免一次滑动多次触发
  bool _hasTriggeredRefresh = false;

  @override
  void addPointer(PointerEvent event) {
    startTrackingPointer(event.pointer);
    // 每次开始触摸时重置状态
    _dragDistance = Offset.zero;
    _hasTriggeredRefresh = false;
  }

  @override
  void handleEvent(PointerEvent event) {
    if (event is PointerMoveEvent) {
      _dragDistance += event.delta;
      // 仅处理下拉动作(dy为正,代表向下滑动),且超过触摸阈值
      if (_dragDistance.dy > kTouchSlop && !_hasTriggeredRefresh) {
        controllerGlobal.getScrollY().then((value) {
          if (value < 5) {
            Fluttertoast.showToast(
              msg: "Refreshing...",
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.CENTER,
              timeInSecForIosWeb: 1,
              backgroundColor: Color.fromARGB(255, 179, 158, 157),
              textColor: Colors.white,
              fontSize: 16.0,
            );
            controllerGlobal.reload();
            _hasTriggeredRefresh = true;
          }
        });
      } else if (_dragDistance.dy < -kTouchSlop) {
        // 上滑时,不处理,交给WebView自身滚动
        resolve(GestureDisposition.rejected);
      }
    } else if (event is PointerUpEvent || event is PointerCancelEvent) {
      // 触摸结束时重置状态
      _dragDistance = Offset.zero;
      _hasTriggeredRefresh = false;
      stopTrackingPointer(event.pointer);
    }
  }

  @override
  String get debugDescription => 'vertical drag for refresh (platform view)';

  @override
  void didStopTrackingLastPointer(int pointer) {}
}

2. 移除冗余的ScrollController监听

外层ListView包裹WebView的结构本身容易引发手势冲突,且_scrollListener的逻辑会重复触发刷新,直接移除相关代码:

class WebViewExampleState extends State<WebViewEx> {
  late bool check, check1;
  // 移除ScrollController相关代码

  @override
  void initState() {
    super.initState();
    check = false;
    check1 = false;
  }

  // 移除_scrollListener方法

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: WillPopScope(
        onWillPop: () async {
          if (await controllerGlobal.canGoBack()) {
            await controllerGlobal.goBack();
            return Future.value(false);
          }
          return Future.value(true);
        },
        // 移除外层ListView,直接使用WebView作为Scaffold的body
        child: Container(
          height: MediaQuery.of(context).size.height,
          child: WebView(
            initialUrl: 'https://doorstep.pro/user/login',
            gestureNavigationEnabled: true,
            debuggingEnabled: true,
            gestureRecognizers: [
              Factory(() => PlatformViewVerticalGestureRecognizer(kind: null)),
            ].toSet(),
            javascriptMode: JavascriptMode.unrestricted,
            onPageFinished: (String url) {
              setState(() {
                bool temp = check;
                check = true;
                if (!temp) controllerGlobal.scrollBy(0, 10);
              });
            },
            onWebViewCreated: (WebViewController webViewController) {
              controllerGlobal = webViewController;
            },
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }

  goBack() {}
}

3. 优化返回按钮逻辑

原onWillPop逻辑不管能不能返回都执行goBack(),会引发错误,修复为只有当WebView可以返回时才执行返回操作。

修复后效果
  • 只有当在WebView顶部向下滑动超过触摸阈值时,才会触发刷新。
  • 点击屏幕任意区域不会触发刷新。
  • 避免了重复刷新的逻辑冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:05:49