webview_scaffold.dart 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import 'dart:async';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/rendering.dart';
  5. import 'base.dart';
  6. class WebviewScaffold extends StatefulWidget {
  7. final PreferredSizeWidget appBar;
  8. final String url;
  9. final bool withJavascript;
  10. final bool supportMultipleWindows;
  11. final bool appCacheEnabled;
  12. final bool clearCache;
  13. final bool clearCookies;
  14. final bool enableAppScheme;
  15. final String userAgent;
  16. final bool primary;
  17. final List<Widget> persistentFooterButtons;
  18. final Widget bottomNavigationBar;
  19. final bool withZoom;
  20. final bool withLocalStorage;
  21. final bool withLocalUrl;
  22. final bool allowFileURLs;
  23. final bool scrollBar;
  24. final bool hidden;
  25. final Widget initialChild;
  26. final Map<String, String> headers;
  27. const WebviewScaffold(
  28. {Key key,
  29. this.appBar,
  30. @required this.url,
  31. this.headers,
  32. this.withJavascript,
  33. this.supportMultipleWindows,
  34. this.appCacheEnabled,
  35. this.clearCache,
  36. this.clearCookies,
  37. this.enableAppScheme,
  38. this.userAgent,
  39. this.primary = true,
  40. this.persistentFooterButtons,
  41. this.bottomNavigationBar,
  42. this.withZoom,
  43. this.withLocalStorage,
  44. this.withLocalUrl,
  45. this.scrollBar,
  46. this.hidden = false,
  47. this.initialChild,
  48. this.allowFileURLs,
  49. })
  50. : super(key: key);
  51. @override
  52. _WebviewScaffoldState createState() => new _WebviewScaffoldState();
  53. }
  54. class _WebviewScaffoldState extends State<WebviewScaffold> {
  55. final webviewReference = new FlutterWebviewPlugin();
  56. Rect _rect;
  57. Timer _resizeTimer;
  58. StreamSubscription<WebViewStateChanged> _onStateChanged;
  59. @override
  60. void initState() {
  61. super.initState();
  62. webviewReference.close();
  63. if (widget.hidden) {
  64. _onStateChanged = webviewReference.onStateChanged.listen((WebViewStateChanged state) {
  65. if (state.type == WebViewState.finishLoad) {
  66. webviewReference.show();
  67. }
  68. });
  69. }
  70. }
  71. @override
  72. void dispose() {
  73. super.dispose();
  74. _resizeTimer?.cancel();
  75. webviewReference.close();
  76. if (widget.hidden) {
  77. _onStateChanged.cancel();
  78. }
  79. webviewReference.dispose();
  80. }
  81. @override
  82. Widget build(BuildContext context) {
  83. return Scaffold(
  84. appBar: widget.appBar,
  85. persistentFooterButtons: widget.persistentFooterButtons,
  86. bottomNavigationBar: widget.bottomNavigationBar,
  87. body: _WebviewPlaceholder(
  88. onRectChanged: (Rect value) {
  89. if (_rect == null) {
  90. _rect = value;
  91. webviewReference.launch(
  92. widget.url,
  93. headers: widget.headers,
  94. withJavascript: widget.withJavascript,
  95. clearCache: widget.clearCache,
  96. clearCookies: widget.clearCookies,
  97. enableAppScheme: widget.enableAppScheme,
  98. userAgent: widget.userAgent,
  99. rect: _rect,
  100. withZoom: widget.withZoom,
  101. withLocalStorage: widget.withLocalStorage,
  102. withLocalUrl: widget.withLocalUrl,
  103. scrollBar: widget.scrollBar,
  104. supportMultipleWindows: widget.supportMultipleWindows,
  105. appCacheEnabled: widget.appCacheEnabled,
  106. allowFileURLs: widget.allowFileURLs,
  107. );
  108. } else {
  109. if (_rect != value) {
  110. _rect = value;
  111. _resizeTimer?.cancel();
  112. _resizeTimer = Timer(const Duration(milliseconds: 250), () {
  113. // avoid resizing to fast when build is called multiple time
  114. webviewReference.resize(_rect);
  115. });
  116. }
  117. }
  118. },
  119. child: widget.initialChild ?? const Center(child: const CircularProgressIndicator()),
  120. ),
  121. );
  122. }
  123. }
  124. class _WebviewPlaceholder extends SingleChildRenderObjectWidget {
  125. const _WebviewPlaceholder({
  126. Key key,
  127. @required this.onRectChanged,
  128. Widget child,
  129. }) : super(key: key, child: child);
  130. final ValueChanged<Rect> onRectChanged;
  131. @override
  132. RenderObject createRenderObject(BuildContext context) {
  133. return _WebviewPlaceholderRender(
  134. onRectChanged: onRectChanged,
  135. );
  136. }
  137. @override
  138. void updateRenderObject(BuildContext context, _WebviewPlaceholderRender renderObject) {
  139. renderObject..onRectChanged = onRectChanged;
  140. }
  141. }
  142. class _WebviewPlaceholderRender extends RenderProxyBox {
  143. ValueChanged<Rect> _callback;
  144. Rect _rect;
  145. _WebviewPlaceholderRender({
  146. RenderBox child,
  147. ValueChanged<Rect> onRectChanged,
  148. }) : _callback = onRectChanged,
  149. super(child);
  150. Rect get rect => _rect;
  151. set onRectChanged(ValueChanged<Rect> callback) {
  152. if (callback != _callback) {
  153. _callback = callback;
  154. notifyRect();
  155. }
  156. }
  157. void notifyRect() {
  158. if (_callback != null && _rect != null) {
  159. _callback(_rect);
  160. }
  161. }
  162. @override
  163. void paint(PaintingContext context, Offset offset) {
  164. super.paint(context, offset);
  165. final rect = offset & size;
  166. if (_rect != rect) {
  167. _rect = rect;
  168. notifyRect();
  169. }
  170. }
  171. }