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
   return !Immutable.is(Immutable.fromJS(newValue), Immutable.fromJS(oldValue));
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
 function getInjectedSource(html, script) {
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
     ${html}
63
     ${html}
77
-    ${scriptString}
64
+    <script>
65
+    ${script}
66
+    </script>
78
     `;
67
     `;
79
-  }
80
 }
68
 }
81
 
69
 
82
 export function getScript(props, getBaseScript, getIframeBaseScript) {
70
 export function getScript(props, getBaseScript, getIframeBaseScript) {
139
 
127
 
140
 export const getCurrentSize = `
128
 export const getCurrentSize = `
141
 function getSize(container) {
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
   return {
132
   return {
145
     height,
133
     height,
146
     width
134
     width

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

7
   requireNativeComponent,
7
   requireNativeComponent,
8
   Animated,
8
   Animated,
9
   DeviceEventEmitter,
9
   DeviceEventEmitter,
10
+  Easing,
10
   StyleSheet,
11
   StyleSheet,
11
   Platform,
12
   Platform,
12
   UIManager,
13
   UIManager,
13
   ViewPropTypes,
14
   ViewPropTypes,
14
-  WebView,
15
-  View
15
+  WebView
16
 } from 'react-native';
16
 } from 'react-native';
17
 
17
 
18
 import PropTypes from 'prop-types';
18
 import PropTypes from 'prop-types';
59
     scalesPageToFit: PropTypes.bool,
59
     scalesPageToFit: PropTypes.bool,
60
     // only works on enable animation
60
     // only works on enable animation
61
     animationDuration: PropTypes.number,
61
     animationDuration: PropTypes.number,
62
+    animationEasing: PropTypes.func,
62
     // offset of rn webView margin
63
     // offset of rn webView margin
63
     heightOffset: PropTypes.number,
64
     heightOffset: PropTypes.number,
64
     // baseUrl not work in android 4.3 or below version
65
     // baseUrl not work in android 4.3 or below version
83
     scalesPageToFit: true,
84
     scalesPageToFit: true,
84
     enableBaseUrl: false,
85
     enableBaseUrl: false,
85
     enableAnimation: true,
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
   constructor(props) {
92
   constructor(props) {
91
     super(props);
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
     isBelowKitKat && DeviceEventEmitter.addListener('webViewBridgeMessage', this.listenWebViewBridgeMessage);
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
       isSizeChanged: false,
100
       isSizeChanged: false,
97
       isSizeMayChange: false,
101
       isSizeMayChange: false,
98
-      height: 0,
99
-      width: getWidth(style),
102
+      height: height,
103
+      width: initWidth,
100
       script: getScript(props, getBaseScript),
104
       script: getScript(props, getBaseScript),
101
       source: enableBaseUrl ? Object.assign({}, source, { baseUrl }) : source
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
   componentDidMount() {
116
   componentDidMount() {
112
     const { source, script } = getUpdatedState(props, enableBaseUrl ? baseUrl : null, getBaseScript);
123
     const { source, script } = getUpdatedState(props, enableBaseUrl ? baseUrl : null, getBaseScript);
113
     const height = style ? style.height : null;
124
     const height = style ? style.height : null;
114
     const width = style ? style.width : null;
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
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
133
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
124
       return {
134
       return {
125
         height,
135
         height,
131
   }
141
   }
132
 
142
 
133
   componentDidUpdate() {
143
   componentDidUpdate() {
134
-    const { height, width, isSizeChanged, isSizeMayChange } = this.state;
144
+    const { height, width, isSizeChanged, isSizeMayChange, heightValue, widthValue } = this.state;
135
     if (isSizeMayChange) {
145
     if (isSizeMayChange) {
136
       this.startInterval();
146
       this.startInterval();
137
       this.setState({ isSizeMayChange: false });
147
       this.setState({ isSizeMayChange: false });
138
     }
148
     }
139
     if (isSizeChanged) {
149
     if (isSizeChanged) {
140
-      const { enableAnimation, animationDuration, onSizeUpdated } = this.props;
150
+      const { enableAnimation, animationDuration, animationEasing, onSizeUpdated, heightOffset } = this.props;
141
       if (enableAnimation) {
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
           handleSizeUpdated(height, width, onSizeUpdated);
164
           handleSizeUpdated(height, width, onSizeUpdated);
147
         });
165
         });
148
       } else {
166
       } else {
178
   }
196
   }
179
 
197
 
180
   startInterval() {
198
   startInterval() {
199
+    if (this.finishInterval === false) {
200
+      return;
201
+    }
181
     this.finishInterval = false;
202
     this.finishInterval = false;
182
     this.interval = setInterval(() => {
203
     this.interval = setInterval(() => {
183
       if (!this.finishInterval) {
204
       if (!this.finishInterval) {
198
     const { height, width } = JSON.parse(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
219
     const { height, width } = JSON.parse(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
199
     const { height: oldHeight, width: oldWidth } = this.state;
220
     const { height: oldHeight, width: oldWidth } = this.state;
200
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
221
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
201
-      this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
202
       this.stopInterval();
222
       this.stopInterval();
203
       this.setState({
223
       this.setState({
204
         isSizeChanged: true,
224
         isSizeChanged: true,
239
   getWebView = webView => (this.webView = webView);
259
   getWebView = webView => (this.webView = webView);
240
 
260
 
241
   render() {
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
     return (
264
     return (
245
-      <View
265
+      <Animated.View
246
         style={[
266
         style={[
247
           styles.container,
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
           style
272
           style
254
         ]}
273
         ]}
270
           // below kitkat
289
           // below kitkat
271
           onChange={this.onMessage}
290
           onChange={this.onMessage}
272
         />
291
         />
273
-      </View>
292
+      </Animated.View>
274
     );
293
     );
275
   }
294
   }
276
 }
295
 }
289
 
308
 
290
 const commonScript = `
309
 const commonScript = `
291
     ${getCurrentSize}
310
     ${getCurrentSize}
292
-    var wrapper = document.createElement('div');
293
-    wrapper.id = 'wrapper';
311
+    var wrapper = document.createElement("div");
312
+    wrapper.id = "wrapper";
294
     while (document.body.firstChild instanceof Node) {
313
     while (document.body.firstChild instanceof Node) {
295
         wrapper.appendChild(document.body.firstChild);
314
         wrapper.appendChild(document.body.firstChild);
296
     }
315
     }
316
+    document.body.appendChild(wrapper);
317
+    var height = 0;
297
 `;
318
 `;
298
 
319
 
299
 const getBaseScript = isBelowKitKat
320
 const getBaseScript = isBelowKitKat
301
       return `
322
       return `
302
     ; 
323
     ; 
303
     ${commonScript}
324
     ${commonScript}
304
-    var height = 0;
305
     var width = ${getWidth(style)};
325
     var width = ${getWidth(style)};
306
     function updateSize() {
326
     function updateSize() {
307
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
327
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
312
       }
332
       }
313
     }
333
     }
314
     (function () {
334
     (function () {
315
-      document.body.appendChild(wrapper);
316
       AutoHeightWebView.onMessage = updateSize;
335
       AutoHeightWebView.onMessage = updateSize;
317
       ${domMutationObserveScript}
336
       ${domMutationObserveScript}
318
     } ());
337
     } ());
322
       return `
341
       return `
323
     ; 
342
     ; 
324
     ${commonScript}
343
     ${commonScript}
325
-    var height = 0;
326
     var width = ${getWidth(style)};
344
     var width = ${getWidth(style)};
327
     function updateSize() {
345
     function updateSize() {
328
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
346
       if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
329
         var size = getSize(document.body.firstChild); 
347
         var size = getSize(document.body.firstChild); 
330
         height = size.height;
348
         height = size.height;
331
         width = size.width;
349
         width = size.width;
332
-        window.postMessage(JSON.stringify({ width, height }));
350
+        window.postMessage(JSON.stringify({ width, height }), '*');
333
       }
351
       }
334
     }
352
     }
335
     (function () {
353
     (function () {
336
-      document.body.appendChild(wrapper);
337
-      document.addEventListener('message', updateSize);
354
+      document.addEventListener("message", updateSize);
338
       ${domMutationObserveScript}
355
       ${domMutationObserveScript}
339
     } ());
356
     } ());
340
   `;
357
   `;

+ 17
- 6
demo/config.js View File

1
 'use strict';
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
 const style0 = `
7
 const style0 = `
8
     p {
8
     p {
9
-        font-size: 25px !important;
9
+        padding: 50px;
10
+        box-sizing: border-box;
10
     }
11
     }
11
 `;
12
 `;
12
 
13
 
13
 const style1 = `
14
 const style1 = `
14
     p {
15
     p {
15
         font-size: 12px !important;
16
         font-size: 12px !important;
17
+        box-sizing: border-box;
16
     }
18
     }
17
 `;
19
 `;
18
 
20
 
19
 const inlineBodyStyle = `
21
 const inlineBodyStyle = `
20
     body {
22
     body {
21
-    display: inline-block 
23
+        display: inline-block;
22
     }
24
     }
23
 `;
25
 `;
24
 
26
 
29
 document.body.style.background = 'cornflowerblue';
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
 const autoWidthScript = `
47
 const autoWidthScript = `
37
 var styleElement = document.createElement('style');
48
 var styleElement = document.createElement('style');