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

Flutter中如何在SingleChildScrollView内实现WebView自适应高度

解决Flutter WebView在SingleChildScrollView中自适应推文高度的问题

针对你使用webview_flutter: ^3.0.0版本,需要在SingleChildScrollView内让WebView自适应推文高度的需求,可通过JavaScript与Flutter通信获取内容高度+动态调整WebView容器高度的方案解决,具体实现如下:

1. 修改HTML生成逻辑,添加高度回调

更新getHtmlString函数,在推文渲染完成后获取容器实际高度,并通过JavaScriptChannel通知Flutter:

String getHtmlString(String tweetId) {
  return '''
  <html>
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <script type="text/javascript" async src="https://platform.twitter.com/widgets.js"></script>
    </head>
    <body style="margin:0; padding:0;">
      <div id="container"></div>
      <script type="text/javascript">
        window.onload = function() {
          // 创建推文并监听渲染完成事件
          twttr.widgets.createTweet(
            '$tweetId',
            document.getElementById('container')
          ).then(function() {
            // 获取推文容器的实际高度
            const containerHeight = document.getElementById('container').offsetHeight;
            // 向Flutter发送高度数据
            window.TweetHeightChannel.postMessage(containerHeight.toString());
          });
        };
      </script>
    </body>
  </html>
  ''';
}

2. 实现自适应高度的WebView组件

创建一个StatefulWidget,通过JavaScriptChannel接收推文高度,动态更新WebView的容器高度,同时禁用WebView自身滚动避免与外层SingleChildScrollView冲突:

class AdaptiveTweetWebView extends StatefulWidget {
  final String tweetId;

  const AdaptiveTweetWebView({Key? key, required this.tweetId}) : super(key: key);

  @override
  State<AdaptiveTweetWebView> createState() => _AdaptiveTweetWebViewState();
}

class _AdaptiveTweetWebViewState extends State<AdaptiveTweetWebView> {
  // 初始默认高度,避免布局异常
  double _tweetHeight = 200;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: _tweetHeight,
      child: WebView(
        initialUrl: Uri.dataFromString(
          getHtmlString(widget.tweetId),
          mimeType: 'text/html',
          encoding: Encoding.getByName('utf-8'),
        ).toString(),
        javascriptMode: JavascriptMode.unrestricted,
        // 配置JavaScriptChannel接收高度数据
        javascriptChannels: {
          JavascriptChannel(
            name: 'TweetHeightChannel',
            onMessageReceived: (JavascriptMessage message) {
              final double? newHeight = double.tryParse(message.message);
              if (newHeight != null && newHeight != _tweetHeight) {
                setState(() {
                  _tweetHeight = newHeight;
                });
              }
            },
          ),
        },
        // 禁用WebView自身滚动,适配外层SingleChildScrollView
        initialSettings: WebViewSettings(
          android: AndroidWebViewSettings(
            scrollEnabled: false,
          ),
          ios: IosWebViewSettings(
            scrollEnabled: false,
          ),
        ),
      ),
    );
  }
}

3. 替换原有固定高度的WebView使用方式

在你的文章渲染逻辑中,替换原来的SizedBox+WebView为新的自适应组件:

final tweetIdRegex = RegExp(r'https://twitter.com/.+?/status/(\d+)');
final match = tweetIdRegex.firstMatch(element.innerHtml);
final extractedId = match?.group(1);
if (extractedId != null) {
  parsedWidgets.add(
    AdaptiveTweetWebView(tweetId: extractedId),
  );
}

关键说明

  • 异步高度获取:通过twttr.widgets.createTweet的Promise回调确保推文完全渲染后再获取高度,避免拿到初始的0高度。
  • 滚动冲突处理:禁用WebView自身滚动,让所有滚动逻辑交由外层SingleChildScrollView处理,避免滑动异常。
  • 初始高度兜底:设置初始默认高度200,防止推文加载前出现布局坍塌问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:53:16