Browse Source

rewirte index.android for dynamic auto height & better animation

iou90 6 years ago
parent
commit
d58b03d7ae
3 changed files with 79 additions and 63 deletions
  1. 6
    18
      autoHeightWebView/common.js
  2. 56
    39
      autoHeightWebView/index.android.js
  3. 17
    6
      demo/config.js

+ 6
- 18
autoHeightWebView/common.js View File

@@ -58,25 +58,13 @@ function isChanged(newValue, oldValue) {
58 58
   return !Immutable.is(Immutable.fromJS(newValue), Immutable.fromJS(oldValue));
59 59
 }
60 60
 
61
-function insertStringAfterAnotherString(raw, searchValue, insertValue) {
62
-  const position = raw.indexOf(searchValue) + searchValue.length;
63
-  return [raw.slice(0, position), insertValue, raw.slice(position)].join('');
64
-}
65
-
66 61
 function getInjectedSource(html, script) {
67
-  const scriptString = `
68
-  <script>
69
-  ${script}
70
-  </script>
71
-  `;
72
-  if (html.startsWith('<html')) {
73
-    return insertStringAfterAnotherString(html, '>', scriptString);
74
-  } else {
75
-    return `
62
+  return `
76 63
     ${html}
77
-    ${scriptString}
64
+    <script>
65
+    ${script}
66
+    </script>
78 67
     `;
79
-  }
80 68
 }
81 69
 
82 70
 export function getScript(props, getBaseScript, getIframeBaseScript) {
@@ -139,8 +127,8 @@ observer.observe(document, {
139 127
 
140 128
 export const getCurrentSize = `
141 129
 function getSize(container) {
142
-  var height = container.clientHeight || document.body.offsetHeight;
143
-  var width = container.clientWidth || document.body.offsetWidth;
130
+  var height = container.offsetHeight || document.body.offsetHeight;
131
+  var width = container.offsetWidth || document.body.offsetWidth;
144 132
   return {
145 133
     height,
146 134
     width

+ 56
- 39
autoHeightWebView/index.android.js View File

@@ -7,12 +7,12 @@ import {
7 7
   requireNativeComponent,
8 8
   Animated,
9 9
   DeviceEventEmitter,
10
+  Easing,
10 11
   StyleSheet,
11 12
   Platform,
12 13
   UIManager,
13 14
   ViewPropTypes,
14
-  WebView,
15
-  View
15
+  WebView
16 16
 } from 'react-native';
17 17
 
18 18
 import PropTypes from 'prop-types';
@@ -59,6 +59,7 @@ export default class AutoHeightWebView extends PureComponent {
59 59
     scalesPageToFit: PropTypes.bool,
60 60
     // only works on enable animation
61 61
     animationDuration: PropTypes.number,
62
+    animationEasing: PropTypes.func,
62 63
     // offset of rn webView margin
63 64
     heightOffset: PropTypes.number,
64 65
     // baseUrl not work in android 4.3 or below version
@@ -83,23 +84,33 @@ export default class AutoHeightWebView extends PureComponent {
83 84
     scalesPageToFit: true,
84 85
     enableBaseUrl: false,
85 86
     enableAnimation: true,
86
-    animationDuration: 555,
87
-    heightOffset: 20
87
+    animationDuration: 255,
88
+    heightOffset: 20,
89
+    animationEasing: Easing.out(Easing.quad)
88 90
   };
89 91
 
90 92
   constructor(props) {
91 93
     super(props);
92
-    const { enableAnimation, style, source, enableBaseUrl } = props;
93
-    enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
94
+    const { enableAnimation, style, source, enableBaseUrl, heightOffset } = props;
94 95
     isBelowKitKat && DeviceEventEmitter.addListener('webViewBridgeMessage', this.listenWebViewBridgeMessage);
95
-    this.state = {
96
+    this.finishInterval = true;
97
+    const initWidth = getWidth(style);
98
+    const height = style ? (style.height ? style.height : 0) : 0;
99
+    let state = {
96 100
       isSizeChanged: false,
97 101
       isSizeMayChange: false,
98
-      height: 0,
99
-      width: getWidth(style),
102
+      height: height,
103
+      width: initWidth,
100 104
       script: getScript(props, getBaseScript),
101 105
       source: enableBaseUrl ? Object.assign({}, source, { baseUrl }) : source
102 106
     };
107
+    if (enableAnimation) {
108
+      Object.assign(state, {
109
+        heightValue: new Animated.Value(height + heightOffset),
110
+        widthValue: new Animated.Value(initWidth)
111
+      });
112
+    }
113
+    this.state = state;
103 114
   }
104 115
 
105 116
   componentDidMount() {
@@ -112,14 +123,13 @@ export default class AutoHeightWebView extends PureComponent {
112 123
     const { source, script } = getUpdatedState(props, enableBaseUrl ? baseUrl : null, getBaseScript);
113 124
     const height = style ? style.height : null;
114 125
     const width = style ? style.width : null;
115
-    // if (source !== prevSource || script !== prevScript) {
116
-    //   console.log(1)
117
-    //   return {
118
-    //     source,
119
-    //     script,
120
-    //     isSizeMayChange: true
121
-    //   };
122
-    // }
126
+    if (source.html !== prevSource.html || source.uri !== prevSource.uri || script !== prevScript) {
127
+      return {
128
+        source,
129
+        script,
130
+        isSizeMayChange: true
131
+      };
132
+    }
123 133
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
124 134
       return {
125 135
         height,
@@ -131,18 +141,26 @@ export default class AutoHeightWebView extends PureComponent {
131 141
   }
132 142
 
133 143
   componentDidUpdate() {
134
-    const { height, width, isSizeChanged, isSizeMayChange } = this.state;
144
+    const { height, width, isSizeChanged, isSizeMayChange, heightValue, widthValue } = this.state;
135 145
     if (isSizeMayChange) {
136 146
       this.startInterval();
137 147
       this.setState({ isSizeMayChange: false });
138 148
     }
139 149
     if (isSizeChanged) {
140
-      const { enableAnimation, animationDuration, onSizeUpdated } = this.props;
150
+      const { enableAnimation, animationDuration, animationEasing, onSizeUpdated, heightOffset } = this.props;
141 151
       if (enableAnimation) {
142
-        Animated.timing(this.opacityAnimatedValue, {
143
-          toValue: 1,
144
-          duration: animationDuration
145
-        }).start(() => {
152
+        Animated.parallel([
153
+          Animated.timing(heightValue, {
154
+            toValue: height + heightOffset,
155
+            easing: animationEasing,
156
+            duration: animationDuration
157
+          }),
158
+          Animated.timing(widthValue, {
159
+            toValue: width,
160
+            easing: animationEasing,
161
+            duration: animationDuration
162
+          })
163
+        ]).start(() => {
146 164
           handleSizeUpdated(height, width, onSizeUpdated);
147 165
         });
148 166
       } else {
@@ -178,6 +196,9 @@ export default class AutoHeightWebView extends PureComponent {
178 196
   }
179 197
 
180 198
   startInterval() {
199
+    if (this.finishInterval === false) {
200
+      return;
201
+    }
181 202
     this.finishInterval = false;
182 203
     this.interval = setInterval(() => {
183 204
       if (!this.finishInterval) {
@@ -198,7 +219,6 @@ export default class AutoHeightWebView extends PureComponent {
198 219
     const { height, width } = JSON.parse(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
199 220
     const { height: oldHeight, width: oldWidth } = this.state;
200 221
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
201
-      this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
202 222
       this.stopInterval();
203 223
       this.setState({
204 224
         isSizeChanged: true,
@@ -239,16 +259,15 @@ export default class AutoHeightWebView extends PureComponent {
239 259
   getWebView = webView => (this.webView = webView);
240 260
 
241 261
   render() {
242
-    const { height, width, script, source } = this.state;
243
-    const { scalesPageToFit, style, scrollEnabled, heightOffset } = this.props;
262
+    const { height, width, script, source, heightValue, widthValue } = this.state;
263
+    const { scalesPageToFit, style, scrollEnabled, heightOffset, enableAnimation } = this.props;
244 264
     return (
245
-      <View
265
+      <Animated.View
246 266
         style={[
247 267
           styles.container,
248 268
           {
249
-            opacity: 1,
250
-            height: height ? height + heightOffset : 0,
251
-            width: width
269
+            height: enableAnimation ? heightValue : height ? height + heightOffset : 0,
270
+            width: enableAnimation ? widthValue : width
252 271
           },
253 272
           style
254 273
         ]}
@@ -270,7 +289,7 @@ export default class AutoHeightWebView extends PureComponent {
270 289
           // below kitkat
271 290
           onChange={this.onMessage}
272 291
         />
273
-      </View>
292
+      </Animated.View>
274 293
     );
275 294
   }
276 295
 }
@@ -289,11 +308,13 @@ const styles = StyleSheet.create({
289 308
 
290 309
 const commonScript = `
291 310
     ${getCurrentSize}
292
-    var wrapper = document.createElement('div');
293
-    wrapper.id = 'wrapper';
311
+    var wrapper = document.createElement("div");
312
+    wrapper.id = "wrapper";
294 313
     while (document.body.firstChild instanceof Node) {
295 314
         wrapper.appendChild(document.body.firstChild);
296 315
     }
316
+    document.body.appendChild(wrapper);
317
+    var height = 0;
297 318
 `;
298 319
 
299 320
 const getBaseScript = isBelowKitKat
@@ -301,7 +322,6 @@ const getBaseScript = isBelowKitKat
301 322
       return `
302 323
     ; 
303 324
     ${commonScript}
304
-    var height = 0;
305 325
     var width = ${getWidth(style)};
306 326
     function updateSize() {
307 327
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
@@ -312,7 +332,6 @@ const getBaseScript = isBelowKitKat
312 332
       }
313 333
     }
314 334
     (function () {
315
-      document.body.appendChild(wrapper);
316 335
       AutoHeightWebView.onMessage = updateSize;
317 336
       ${domMutationObserveScript}
318 337
     } ());
@@ -322,19 +341,17 @@ const getBaseScript = isBelowKitKat
322 341
       return `
323 342
     ; 
324 343
     ${commonScript}
325
-    var height = 0;
326 344
     var width = ${getWidth(style)};
327 345
     function updateSize() {
328 346
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
329 347
         var size = getSize(document.body.firstChild); 
330 348
         height = size.height;
331 349
         width = size.width;
332
-        window.postMessage(JSON.stringify({ width, height }));
350
+        window.postMessage(JSON.stringify({ width, height }), '*');
333 351
       }
334 352
     }
335 353
     (function () {
336
-      document.body.appendChild(wrapper);
337
-      document.addEventListener('message', updateSize);
354
+      document.addEventListener("message", updateSize);
338 355
       ${domMutationObserveScript}
339 356
     } ());
340 357
   `;

+ 17
- 6
demo/config.js View File

@@ -1,24 +1,26 @@
1 1
 'use strict';
2 2
 
3
-const autoHeightHtml0 = `<p style="font-weight: 400;font-style: normal;font-size: 21px;line-height: 1.58;letter-spacing: -.003em;">Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. <span style="background-color: transparent !important;background-image: linear-gradient(to bottom, rgba(146, 249, 190, 1), rgba(146, 249, 190, 1));">If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn’t only tag the piece with “moving”. I’d also use the tags “pets”, “marriage”, “career change”, and “travel tips”.</span></p>`;
3
+const autoHeightHtml0 = `<p style="font-weight: 400;font-style: normal;font-size: 21px;line-height: 1.58;letter-spacing: -.003em;">Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. <span style="background-color: transparent !important;background-image: linear-gradient(to bottom, rgba(146, 249, 190, 1), rgba(146, 249, 190, 1));">If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn't only tag the piece with "moving". I’d also use the tags "pets", "marriage", "career change", and "travel tips".</span></p>`;
4 4
 
5
-const autoHeightHtml1 = `Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn’t only tag the piece with “moving”. I’d also use the tags “pets”, “marriage”, “career change”, and “travel tips”.`;
5
+const autoHeightHtml1 = `Tags are great for describing the essence of your story in a single word or phrase, but stories are rarely about a single thing. If I pen a story about moving across the country to start a new job in a car with my husband, two cats, a dog, and a tarantula, I wouldn’t only tag the piece with "moving".`;
6 6
 
7 7
 const style0 = `
8 8
     p {
9
-        font-size: 25px !important;
9
+        padding: 50px;
10
+        box-sizing: border-box;
10 11
     }
11 12
 `;
12 13
 
13 14
 const style1 = `
14 15
     p {
15 16
         font-size: 12px !important;
17
+        box-sizing: border-box;
16 18
     }
17 19
 `;
18 20
 
19 21
 const inlineBodyStyle = `
20 22
     body {
21
-    display: inline-block 
23
+        display: inline-block;
22 24
     }
23 25
 `;
24 26
 
@@ -29,9 +31,18 @@ document.head.appendChild(styleElement);
29 31
 document.body.style.background = 'cornflowerblue';
30 32
 `;
31 33
 
32
-const autoWidthHtml0 = `<p style="display: inline-block;background-color: transparent !important;background-image: linear-gradient(to bottom, rgba(146, 249, 190, 1), rgba(146, 249, 190, 1));font-weight: 400;font-style: normal;font-size: 21px;line-height: 1.58;letter-spacing: -.003em;">hey</p>`;
34
+const autoWidthHtml0 = `
35
+<html>
36
+<head>
37
+  <meta name="viewport" content="target-densitydpi=device-dpi, initial-scale=1.0, user-scalable=no" />
38
+</head>
39
+<p style="display: inline;background-color: transparent !important;background-image: linear-gradient(to bottom, rgba(146, 249, 190, 1), rgba(146, 249, 190, 1));font-weight: 400;font-style: normal;zoom:1;font-size: 21px;line-height: 1.58;letter-spacing: -.003em;">hey</p>
40
+</html>
41
+`;
33 42
 
34
-const autoWidthHtml1 = `<p style="display: inline-block;background-color: transparent !important;font-size: 35px;">hey</p>`;
43
+const autoWidthHtml1 = `
44
+<p style="display: inline;background-color: transparent !important;">easy</p>
45
+`;
35 46
 
36 47
 const autoWidthScript = `
37 48
 var styleElement = document.createElement('style');