Skip to content

Commit ec3de70

Browse files
authored
Merge pull request #178 from slightfoot/master
Fix rect capture on WebviewScaffold
2 parents fc48ca7 + 0e7cf13 commit ec3de70

File tree

2 files changed

+155
-119
lines changed

2 files changed

+155
-119
lines changed

example/lib/main.dart

Lines changed: 67 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -160,77 +160,76 @@ class _MyHomePageState extends State<MyHomePage> {
160160
appBar: new AppBar(
161161
title: const Text('Plugin example app'),
162162
),
163-
body: new Column(
164-
mainAxisAlignment: MainAxisAlignment.center,
165-
children: [
166-
new Container(
167-
padding: const EdgeInsets.all(24.0),
168-
child: new TextField(controller: _urlCtrl),
169-
),
170-
new RaisedButton(
171-
onPressed: () {
172-
flutterWebviewPlugin.launch(selectedUrl,
173-
rect: new Rect.fromLTWH(
174-
0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
175-
userAgent: kAndroidUserAgent);
176-
},
177-
child: const Text('Open Webview (rect)'),
178-
),
179-
new RaisedButton(
180-
onPressed: () {
181-
flutterWebviewPlugin.launch(selectedUrl, hidden: true);
182-
},
183-
child: const Text('Open "hidden" Webview'),
184-
),
185-
new RaisedButton(
186-
onPressed: () {
187-
flutterWebviewPlugin.launch(selectedUrl);
188-
},
189-
child: const Text('Open Fullscreen Webview'),
190-
),
191-
new RaisedButton(
192-
onPressed: () {
193-
Navigator.of(context).pushNamed('/widget');
194-
},
195-
child: const Text('Open widget webview'),
196-
),
197-
new Container(
198-
padding: const EdgeInsets.all(24.0),
199-
child: new TextField(controller: _codeCtrl),
200-
),
201-
new RaisedButton(
202-
onPressed: () {
203-
final future =
204-
flutterWebviewPlugin.evalJavascript(_codeCtrl.text);
205-
future.then((String result) {
206-
setState(() {
207-
_history.add('eval: $result');
163+
body: SingleChildScrollView(
164+
child: new Column(
165+
mainAxisAlignment: MainAxisAlignment.center,
166+
children: [
167+
new Container(
168+
padding: const EdgeInsets.all(24.0),
169+
child: new TextField(controller: _urlCtrl),
170+
),
171+
new RaisedButton(
172+
onPressed: () {
173+
flutterWebviewPlugin.launch(selectedUrl,
174+
rect: new Rect.fromLTWH(0.0, 0.0, MediaQuery.of(context).size.width, 300.0), userAgent: kAndroidUserAgent);
175+
},
176+
child: const Text('Open Webview (rect)'),
177+
),
178+
new RaisedButton(
179+
onPressed: () {
180+
flutterWebviewPlugin.launch(selectedUrl, hidden: true);
181+
},
182+
child: const Text('Open "hidden" Webview'),
183+
),
184+
new RaisedButton(
185+
onPressed: () {
186+
flutterWebviewPlugin.launch(selectedUrl);
187+
},
188+
child: const Text('Open Fullscreen Webview'),
189+
),
190+
new RaisedButton(
191+
onPressed: () {
192+
Navigator.of(context).pushNamed('/widget');
193+
},
194+
child: const Text('Open widget webview'),
195+
),
196+
new Container(
197+
padding: const EdgeInsets.all(24.0),
198+
child: new TextField(controller: _codeCtrl),
199+
),
200+
new RaisedButton(
201+
onPressed: () {
202+
final future = flutterWebviewPlugin.evalJavascript(_codeCtrl.text);
203+
future.then((String result) {
204+
setState(() {
205+
_history.add('eval: $result');
206+
});
208207
});
209-
});
210-
},
211-
child: const Text('Eval some javascript'),
212-
),
213-
new RaisedButton(
214-
onPressed: () {
215-
setState(() {
216-
_history.clear();
217-
});
218-
flutterWebviewPlugin.close();
219-
},
220-
child: const Text('Close'),
221-
),
222-
new RaisedButton(
223-
onPressed: () {
224-
flutterWebviewPlugin.getCookies().then((m) {
208+
},
209+
child: const Text('Eval some javascript'),
210+
),
211+
new RaisedButton(
212+
onPressed: () {
225213
setState(() {
226-
_history.add('cookies: $m');
214+
_history.clear();
215+
});
216+
flutterWebviewPlugin.close();
217+
},
218+
child: const Text('Close'),
219+
),
220+
new RaisedButton(
221+
onPressed: () {
222+
flutterWebviewPlugin.getCookies().then((m) {
223+
setState(() {
224+
_history.add('cookies: $m');
225+
});
227226
});
228-
});
229-
},
230-
child: const Text('Cookies'),
231-
),
232-
new Text(_history.join('\n'))
233-
],
227+
},
228+
child: const Text('Cookies'),
229+
),
230+
new Text(_history.join('\n'))
231+
],
232+
),
234233
),
235234
);
236235
}

lib/src/webview_scaffold.dart

Lines changed: 88 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:flutter/foundation.dart';
44
import 'package:flutter/material.dart';
5+
import 'package:flutter/rendering.dart';
56

67
import 'base.dart';
78

@@ -60,72 +61,108 @@ class _WebviewScaffoldState extends State<WebviewScaffold> {
6061
@override
6162
void dispose() {
6263
super.dispose();
64+
_resizeTimer?.cancel();
6365
webviewReference.close();
6466
webviewReference.dispose();
6567
}
6668

6769
@override
6870
Widget build(BuildContext context) {
69-
if (_rect == null) {
70-
_rect = _buildRect(context);
71-
webviewReference.launch(widget.url,
72-
headers: widget.headers,
73-
withJavascript: widget.withJavascript,
74-
clearCache: widget.clearCache,
75-
clearCookies: widget.clearCookies,
76-
enableAppScheme: widget.enableAppScheme,
77-
userAgent: widget.userAgent,
78-
rect: _rect,
79-
withZoom: widget.withZoom,
80-
withLocalStorage: widget.withLocalStorage,
81-
withLocalUrl: widget.withLocalUrl,
82-
scrollBar: widget.scrollBar);
83-
} else {
84-
final rect = _buildRect(context);
85-
if (_rect != rect) {
86-
_rect = rect;
87-
_resizeTimer?.cancel();
88-
_resizeTimer = new Timer(new Duration(milliseconds: 300), () {
89-
// avoid resizing to fast when build is called multiple time
90-
webviewReference.resize(_rect);
91-
});
92-
}
93-
}
94-
return new Scaffold(
95-
appBar: widget.appBar,
96-
persistentFooterButtons: widget.persistentFooterButtons,
97-
bottomNavigationBar: widget.bottomNavigationBar,
98-
body: const Center(child: const CircularProgressIndicator()));
71+
return Scaffold(
72+
appBar: widget.appBar,
73+
persistentFooterButtons: widget.persistentFooterButtons,
74+
bottomNavigationBar: widget.bottomNavigationBar,
75+
body: _WebviewPlaceholder(
76+
onRectChanged: (Rect value) {
77+
if (_rect == null) {
78+
_rect = value;
79+
webviewReference.launch(
80+
widget.url,
81+
headers: widget.headers,
82+
withJavascript: widget.withJavascript,
83+
clearCache: widget.clearCache,
84+
clearCookies: widget.clearCookies,
85+
enableAppScheme: widget.enableAppScheme,
86+
userAgent: widget.userAgent,
87+
rect: _rect,
88+
withZoom: widget.withZoom,
89+
withLocalStorage: widget.withLocalStorage,
90+
withLocalUrl: widget.withLocalUrl,
91+
scrollBar: widget.scrollBar,
92+
);
93+
} else {
94+
if (_rect != value) {
95+
_rect = value;
96+
_resizeTimer?.cancel();
97+
_resizeTimer = Timer(const Duration(milliseconds: 250), () {
98+
// avoid resizing to fast when build is called multiple time
99+
webviewReference.resize(_rect);
100+
});
101+
}
102+
}
103+
},
104+
child: const Center(
105+
child: CircularProgressIndicator(),
106+
),
107+
),
108+
);
99109
}
110+
}
100111

101-
Rect _buildRect(BuildContext context) {
102-
final fullscreen = widget.appBar == null;
112+
class _WebviewPlaceholder extends SingleChildRenderObjectWidget {
113+
const _WebviewPlaceholder({
114+
Key key,
115+
@required this.onRectChanged,
116+
Widget child,
117+
}) : super(key: key, child: child);
103118

104-
final mediaQuery = MediaQuery.of(context);
105-
final topPadding = widget.primary ? mediaQuery.padding.top : 0.0;
106-
final top =
107-
fullscreen ? 0.0 : widget.appBar.preferredSize.height + topPadding;
119+
final ValueChanged<Rect> onRectChanged;
108120

109-
var height = mediaQuery.size.height - top;
121+
@override
122+
RenderObject createRenderObject(BuildContext context) {
123+
return _WebviewPlaceholderRender(
124+
onRectChanged: onRectChanged,
125+
);
126+
}
110127

111-
if (widget.bottomNavigationBar != null) {
112-
height -= 56.0 +
113-
mediaQuery.padding
114-
.bottom; // todo(lejard_h) find a way to determine bottomNavigationBar programmatically
115-
}
128+
@override
129+
void updateRenderObject(BuildContext context, _WebviewPlaceholderRender renderObject) {
130+
renderObject..onRectChanged = onRectChanged;
131+
}
132+
}
116133

117-
if (widget.persistentFooterButtons != null) {
118-
height -=
119-
53.0; // todo(lejard_h) find a way to determine persistentFooterButtons programmatically
120-
if (widget.bottomNavigationBar == null) {
121-
height -= mediaQuery.padding.bottom;
122-
}
134+
class _WebviewPlaceholderRender extends RenderProxyBox {
135+
ValueChanged<Rect> _callback;
136+
Rect _rect;
137+
138+
_WebviewPlaceholderRender({
139+
RenderBox child,
140+
ValueChanged<Rect> onRectChanged,
141+
}) : _callback = onRectChanged,
142+
super(child);
143+
144+
Rect get rect => _rect;
145+
146+
set onRectChanged(ValueChanged<Rect> callback) {
147+
if (callback != _callback) {
148+
_callback = callback;
149+
notifyRect();
123150
}
151+
}
124152

125-
if (height < 0.0) {
126-
height = 0.0;
153+
void notifyRect() {
154+
if (_callback != null && _rect != null) {
155+
_callback(_rect);
127156
}
157+
}
128158

129-
return new Rect.fromLTWH(0.0, top, mediaQuery.size.width, height);
159+
@override
160+
void paint(PaintingContext context, Offset offset) {
161+
super.paint(context, offset);
162+
final rect = offset & size;
163+
if (_rect != rect) {
164+
_rect = rect;
165+
notifyRect();
166+
}
130167
}
131168
}

0 commit comments

Comments
 (0)