Flutter Webview 滑动不流畅优化笔记

1,267 阅读2分钟

Webview does not scroll smoothly #27180

github.com/flutter/flu…

Scrolling on the webview example is not smooth, also happens with animations. Compare with a native webview embedded on an Android app.

Will it be possible to have smooth scroll using webview or it is a known limitation of platform views?

android studio flutter attach 模式下输出日志

flutter attach does not show logs #70473

flutter logs & flutter attach

动画性能优化

www.wodecun.com/blog/8140.h…

Webview animation is slow on Android #52211

github.com/flutter/flu…

stackoverflow.com/questions/7…

//webview 添加手势

VerticalDragGestureRecognizer

相关代码块

preferredSize: Size(double.infinity, 0),
child: AppBar(
title: Text(""),
backgroundColor: Colors.deepPurple,
),
),
import 'package:webview_flutter/webview_flutter.dart';
import 'package:share/share.dart';

class WebViewPage extends StatefulWidget {
  final urllink;
  WebViewPage(this.urllink);
  @override
  _WebViewPageState createState() => _WebViewPageState(this.urllink);
}

class _WebViewPageState extends State<WebViewPage> {
  var _url;
  final key = UniqueKey();
  _WebViewPageState(this._url);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(icon: Icon(Icons.share), onPressed: share)
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: WebView(
              gestureRecognizers: [Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer())].toSet(),//error line
              javascriptMode: JavascriptMode.unrestricted,
              key: key,
              initialUrl: _url,
            ),
          )
        ],
      ),
    );
  }

  void share() {
    String shareurl = _url.toString();
    Share.share(shareurl);
  }
}

最终解决

背景: 混合框架中对flutter webview 做了封装;通过记录用户阅读时长给到响应的奖励; 在webview上会显示一个阅读进度圈圈动画,大概30秒会转一圈;



import 'dart:math';
import 'package:flutter/material.dart';

class GradientCircularProgress extends StatelessWidget {
  final double strokeWidth;
  final double radius;
  final double value;
  final bool strokeCapRound;
  final Color backgroundColor;
  final double totalAngle;
  final List<Color> colors;
  final List<double> stops;

  GradientCircularProgress(
      {this.strokeWidth = 2,
      @required this.radius,
      this.value,
      this.strokeCapRound = false,
      this.backgroundColor = const Color(0xFFEEEEEE),
      this.totalAngle = 2 * pi,
      @required this.colors,
      this.stops});

  @override
  Widget build(BuildContext context) {
    double _offset = 0;
    if (strokeCapRound) {
      _offset = asin(strokeWidth / (radius * 2 - strokeWidth));
    }
    var _colors = colors;
    if (_colors == null) {
      Color color = Theme.of(context).accentColor;
      _colors = [color, color];
    }
    return Transform.rotate(
      angle: -pi / 2 - _offset,
      child: CustomPaint(
        size: Size.fromRadius(radius),
        painter: _GradientCircularProgressPainter(
            colors: _colors,
            strokeWidth: strokeWidth,
            strokeCapRound: strokeCapRound,
            backgroundColor: backgroundColor,
            value: value,
            total: totalAngle,
            radius: radius),
      ),
    );
  }
}

//画笔
class _GradientCircularProgressPainter extends CustomPainter {
  final double strokeWidth;
  final bool strokeCapRound;
  final double value;
  final Color backgroundColor;
  final List<Color> colors;
  final double total;
  final double radius;
  final List<double> stops;

  _GradientCircularProgressPainter(
      {this.strokeWidth: 10.0,
      this.strokeCapRound: false,
      this.backgroundColor = Colors.white,
      this.radius,
      this.total = 2 * pi,
      @required this.colors,
      this.stops,
      this.value});

  @override
  void paint(Canvas canvas, Size size) {
    if (radius != null) {
      size = Size.fromRadius(radius);
    }
    double _offset = strokeWidth / 2;
    double _value = value ?? 0;
    _value = _value.clamp(0, 1) * total;
    double _start = 0;

    if (strokeCapRound) {
      _start = asin(strokeWidth / (size.width - strokeWidth));
    }

    Rect rect = Offset(_offset, _offset) &
        Size(size.width - strokeWidth, size.height - strokeWidth);

    var paint = Paint()
      ..strokeCap = strokeCapRound ? StrokeCap.round : StrokeCap.butt
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true
      ..strokeWidth = strokeWidth;

    //backgroundColor
    var paint2 = Paint()
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true
      ..color = Colors.grey[200]
      ..strokeWidth = strokeWidth;

    canvas.drawArc(rect, _start, total, false, paint2);

    if (_value > 0) {
      paint.shader = SweepGradient(
              colors: colors, startAngle: 0, endAngle: _value, stops: stops)
          .createShader(rect);

      canvas.drawArc(rect, _start, _value, false, paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
```
```

问题
发现部分Android机型滑动不流畅,卡顿感特别明显;
最终定位到是因为这个阅读转圈圈小组件影响;
最后进一步确认只要有webview组件的页面,使用了```AnimationController``` 都会存在卡顿;
AnimationController.value 会不断的进行创建UI;

解决
自己写了一个计时器进行转圈圈动画刷新,300毫秒刷新一次;动画效果也的到保证,webview滑动体验提升300%