Pārlūkot izejas kodu

[RN] Refactor SideBar layout and animation

Layout:

Use an absolute-fill view as the background with the sidebar on top of. This
greatly simplifies styling, as there is no need to calculate how large the
backdrop needs to be.

Animation:

Switch to a translateX transform animation. This serves 2 purposes: first,
there seems to be a bug somewhere in React Native 0.51-0.55 where the content
that is being animated starts to be clipped. Very weird! But more importantly,
translateX transmorm animations are supported by the native animation driver!

https://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html
8f5ebe5952/Libraries/Animated/src/NativeAnimatedHelper.js (L138-L176)

This makes the animation more performant and buttery smooth.

Some small cleanups are also included here.
master
Saúl Ibarra Corretgé 7 gadus atpakaļ
vecāks
revīzija
c700261852

+ 39
- 73
react/features/base/react/components/native/SideBar.js Parādīt failu

1
 // @flow
1
 // @flow
2
 
2
 
3
-import React, { Component } from 'react';
3
+import React, { Component, type Node } from 'react';
4
 import {
4
 import {
5
     Animated,
5
     Animated,
6
-    Dimensions,
7
     TouchableWithoutFeedback,
6
     TouchableWithoutFeedback,
8
     View
7
     View
9
 } from 'react-native';
8
 } from 'react-native';
15
  */
14
  */
16
 type Props = {
15
 type Props = {
17
 
16
 
18
-    /**
19
-     * The local participant's avatar
20
-     */
21
-    _avatar: string,
22
-
23
     /**
17
     /**
24
      * The children of the Component
18
      * The children of the Component
25
      */
19
      */
26
-    children: React$Node,
20
+    children: Node,
27
 
21
 
28
     /**
22
     /**
29
      * Callback to notify the containing Component that the sidebar is
23
      * Callback to notify the containing Component that the sidebar is
47
      */
41
      */
48
     showOverlay: boolean,
42
     showOverlay: boolean,
49
 
43
 
50
-    /**
51
-     * Indicates whether the side bar is visible or not.
52
-     */
53
-    showSideBar: boolean,
54
-
55
     /**
44
     /**
56
      * The native animation object.
45
      * The native animation object.
57
      */
46
      */
62
  * A generic animated side bar to be used for left side menus
51
  * A generic animated side bar to be used for left side menus
63
  */
52
  */
64
 export default class SideBar extends Component<Props, State> {
53
 export default class SideBar extends Component<Props, State> {
65
-    _mounted: boolean;
66
-
67
     /**
54
     /**
68
      * Initializes a new {@code SideBar} instance.
55
      * Initializes a new {@code SideBar} instance.
69
      *
56
      *
74
 
61
 
75
         this.state = {
62
         this.state = {
76
             showOverlay: false,
63
             showOverlay: false,
77
-            showSideBar: false,
78
-            sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
64
+            sliderAnimation: new Animated.Value(0)
79
         };
65
         };
80
 
66
 
81
-        this._getContainerStyle = this._getContainerStyle.bind(this);
82
         this._onHideMenu = this._onHideMenu.bind(this);
67
         this._onHideMenu = this._onHideMenu.bind(this);
83
-        this._setShow = this._setShow.bind(this);
84
-
85
-        this._setShow(props.show);
86
     }
68
     }
87
 
69
 
88
     /**
70
     /**
91
      * @inheritdoc
73
      * @inheritdoc
92
      */
74
      */
93
     componentDidMount() {
75
     componentDidMount() {
94
-        this._mounted = true;
76
+        this._setShow(this.props.show);
95
     }
77
     }
96
 
78
 
97
     /**
79
     /**
112
      */
94
      */
113
     render() {
95
     render() {
114
         return (
96
         return (
115
-            <Animated.View
116
-                style = { this._getContainerStyle() } >
117
-                <View style = { styles.sideMenuContent }>
118
-                    {
119
-                        this.props.children
120
-                    }
121
-                </View>
122
-                <TouchableWithoutFeedback
123
-                    onPress = { this._onHideMenu }
124
-                    style = { styles.sideMenuShadowTouchable } >
125
-                    <View style = { styles.sideMenuShadow } />
126
-                </TouchableWithoutFeedback>
127
-            </Animated.View>
97
+            <View
98
+                pointerEvents = 'box-none'
99
+                style = { styles.sideMenuContainer } >
100
+                {
101
+                    this.state.showOverlay
102
+                        && <TouchableWithoutFeedback
103
+                            onPress = { this._onHideMenu } >
104
+                            <View style = { styles.sideMenuShadow } />
105
+                        </TouchableWithoutFeedback>
106
+                }
107
+                <Animated.View style = { this._getContentStyle() }>
108
+                    { this.props.children }
109
+                </Animated.View>
110
+            </View>
128
         );
111
         );
129
     }
112
     }
130
 
113
 
131
-    _getContainerStyle: () => Array<Object>
114
+    _getContentStyle: () => Array<Object>;
132
 
115
 
133
     /**
116
     /**
134
-     * Assembles a style array for the container.
117
+     * Assembles a style array for the sidebar content.
135
      *
118
      *
136
      * @private
119
      * @private
137
      * @returns {Array<Object>}
120
      * @returns {Array<Object>}
138
      */
121
      */
139
-    _getContainerStyle() {
122
+    _getContentStyle() {
140
         const { sliderAnimation } = this.state;
123
         const { sliderAnimation } = this.state;
141
-        const { height, width } = Dimensions.get('window');
142
-
143
-        return [
144
-            styles.sideMenuContainer,
145
-            {
146
-                left: sliderAnimation,
147
-                width: this.state.showOverlay
148
-                    ? Math.max(height, width) + SIDEBAR_WIDTH : SIDEBAR_WIDTH
149
-            }
150
-        ];
124
+        const transformStyle
125
+            = { transform: [ { translateX: sliderAnimation } ] };
126
+
127
+        return [ styles.sideMenuContent, transformStyle ];
151
     }
128
     }
152
 
129
 
153
     _onHideMenu: () => void;
130
     _onHideMenu: () => void;
163
 
140
 
164
         const { onHide } = this.props;
141
         const { onHide } = this.props;
165
 
142
 
166
-        if (typeof onHide === 'function') {
167
-            onHide();
168
-        }
143
+        onHide && onHide();
169
     }
144
     }
170
 
145
 
171
     _setShow: (boolean) => void;
146
     _setShow: (boolean) => void;
178
      * @returns {void}
153
      * @returns {void}
179
      */
154
      */
180
     _setShow(show) {
155
     _setShow(show) {
181
-        if (this.state.showSideBar !== show) {
182
-            if (show) {
183
-                this.setState({
184
-                    showOverlay: true
185
-                });
186
-            }
187
-
188
-            Animated
189
-                .timing(
190
-                    this.state.sliderAnimation,
191
-                    { toValue: show ? 0 : -SIDEBAR_WIDTH })
192
-                .start(animationState => {
193
-                    if (animationState.finished && !show) {
194
-                        this.setState({
195
-                            showOverlay: false
196
-                        });
197
-                    }
198
-                });
156
+        if (show) {
157
+            this.setState({ showOverlay: true });
199
         }
158
         }
200
 
159
 
201
-        if (this._mounted) {
202
-            this.setState({
203
-                showSideBar: show
160
+        Animated
161
+            .timing(
162
+                this.state.sliderAnimation,
163
+                {
164
+                    toValue: show ? SIDEBAR_WIDTH : 0,
165
+                    useNativeDriver: true
166
+                })
167
+            .start(animationState => {
168
+                if (animationState.finished && !show) {
169
+                    this.setState({ showOverlay: false });
170
+                }
204
             });
171
             });
205
-        }
206
     }
172
     }
207
 }
173
 }

+ 8
- 17
react/features/base/react/components/native/styles.js Parādīt failu

278
      * The topmost container of the side bar.
278
      * The topmost container of the side bar.
279
      */
279
      */
280
     sideMenuContainer: {
280
     sideMenuContainer: {
281
-        bottom: 0,
282
-        flexDirection: 'row',
283
-        left: -SIDEBAR_WIDTH,
284
-        position: 'absolute',
285
-        top: 0,
286
-        width: SIDEBAR_WIDTH
281
+        ...StyleSheet.absoluteFillObject
287
     },
282
     },
288
 
283
 
289
     /**
284
     /**
290
      * The container of the actual content of the side menu.
285
      * The container of the actual content of the side menu.
291
      */
286
      */
292
     sideMenuContent: {
287
     sideMenuContent: {
288
+        bottom: 0,
289
+        left: -SIDEBAR_WIDTH,
290
+        position: 'absolute',
291
+        top: 0,
293
         width: SIDEBAR_WIDTH
292
         width: SIDEBAR_WIDTH
294
     },
293
     },
295
 
294
 
296
     /**
295
     /**
297
-     * The opaque area that covers the rest of the scren, when
296
+     * The opaque area that covers the rest of the screen, when
298
      * the side bar is open.
297
      * the side bar is open.
299
      */
298
      */
300
     sideMenuShadow: {
299
     sideMenuShadow: {
301
-        backgroundColor: 'rgba(0, 0, 0, 0.5)',
302
-        flex: 1
303
-    },
304
-
305
-    /**
306
-     * The touchable area of the rest of the screen that closes the side bar
307
-     * when tapped.
308
-     */
309
-    sideMenuShadowTouchable: {
310
-        flex: 1
300
+        ...StyleSheet.absoluteFillObject,
301
+        backgroundColor: 'rgba(0, 0, 0, 0.5)'
311
     }
302
     }
312
 };
303
 };
313
 
304
 

Notiek ielāde…
Atcelt
Saglabāt