Create a RTLExample for OSS
Reviewed By: fkgozali Differential Revision: D3740559 fbshipit-source-id: 79271abe7ef5c723e934da24884ff777aea0acc3
This commit is contained in:
parent
1aef7e4629
commit
53d3f94175
|
@ -0,0 +1,411 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Here's the Right-to-Left(RTL) example page with:
|
||||
* - a button to force flip UI layout to RTL
|
||||
* - base layout example and text example
|
||||
* - two custom examples for RTL design
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {
|
||||
Alert,
|
||||
Animated,
|
||||
I18nManager,
|
||||
Image,
|
||||
PanResponder,
|
||||
PixelRatio,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableWithoutFeedback,
|
||||
Switch,
|
||||
View,
|
||||
} = ReactNative;
|
||||
|
||||
const UIExplorerPage = require('./UIExplorerPage');
|
||||
const UIExplorerBlock = require('./UIExplorerBlock');
|
||||
|
||||
const AnimatedImage = Animated.createAnimatedComponent(Image);
|
||||
|
||||
type State = {
|
||||
toggleStatus: any,
|
||||
pan: Object,
|
||||
linear: Object,
|
||||
isRTL: boolean,
|
||||
windowWidth: number,
|
||||
};
|
||||
|
||||
const SCALE = PixelRatio.get();
|
||||
const IMAGE_DIMENSION = 100 * SCALE;
|
||||
const IMAGE_SIZE = [IMAGE_DIMENSION, IMAGE_DIMENSION];
|
||||
|
||||
const IS_RTL = I18nManager.isRTL;
|
||||
|
||||
function ListItem(props) {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<View style={styles.column1}>
|
||||
<Image
|
||||
source={props.imageSource}
|
||||
style={styles.icon}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.column2}>
|
||||
<View style={styles.textBox}>
|
||||
<Text>
|
||||
Text
|
||||
Text
|
||||
Text
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.column3}>
|
||||
<View style={styles.smallButton}>
|
||||
<Text style={styles.fontSizeSmall}>
|
||||
Button
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function TextAlignmentExample(props) {
|
||||
return (
|
||||
<UIExplorerBlock
|
||||
title={props.title}
|
||||
description={props.description}>
|
||||
<View>
|
||||
<Text style={props.style}>
|
||||
Left-to-Right language without text alignment.
|
||||
</Text>
|
||||
<Text style={props.style}>
|
||||
من اليمين إلى اليسار اللغة دون محاذاة النص .
|
||||
</Text>
|
||||
<Text style={props.style}>
|
||||
מימין לשמאל השפה בלי יישור טקסט .
|
||||
</Text>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
);
|
||||
}
|
||||
|
||||
function AnimationBlock(props) {
|
||||
return (
|
||||
<View style={styles.block}>
|
||||
<TouchableWithoutFeedback onPress={props.onPress}>
|
||||
<AnimatedImage
|
||||
style={[styles.img, props.imgStyle]}
|
||||
source={require('./Thumbnails/poke.png')}
|
||||
/>
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
class RTLExample extends React.Component {
|
||||
static title = 'RTLExample';
|
||||
static description = 'Examples to show how to apply components to RTL layout.';
|
||||
|
||||
state: State;
|
||||
props: any;
|
||||
_panResponder: Object;
|
||||
|
||||
constructor(props: Object) {
|
||||
super(props);
|
||||
const pan = new Animated.ValueXY();
|
||||
|
||||
this._panResponder = PanResponder.create({
|
||||
onStartShouldSetPanResponder: () => true,
|
||||
onPanResponderGrant: this._onPanResponderGrant,
|
||||
onPanResponderMove: Animated.event([
|
||||
null, {dx: pan.x, dy: pan.y},
|
||||
]),
|
||||
onPanResponderRelease: this._onPanResponderEnd,
|
||||
onPanResponderTerminate: this._onPanResponderEnd,
|
||||
});
|
||||
|
||||
this.state = {
|
||||
toggleStatus: {},
|
||||
pan,
|
||||
linear: new Animated.Value(0),
|
||||
isRTL: IS_RTL,
|
||||
windowWidth: 0,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
onLayout={this._onLayout}>
|
||||
<UIExplorerPage title={'Right-to-Left (RTL) UI Layout'}>
|
||||
<UIExplorerBlock title={'Current Layout Direction'}>
|
||||
<View style={styles.directionBox}>
|
||||
<Text style={styles.directionText}>
|
||||
{this.state.isRTL ? 'Right-to-Left' : 'Left-to-Right'}
|
||||
</Text>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title={'Quickly Test RTL Layout'}>
|
||||
<View style={styles.flexDirectionRow}>
|
||||
<Text style={styles.switchRowTextView}>
|
||||
forceRTL
|
||||
</Text>
|
||||
<View style={styles.switchRowSwitchView}>
|
||||
<Switch
|
||||
onValueChange={this._onDirectionChange}
|
||||
style={styles.rightAlignStyle}
|
||||
value={this.state.isRTL} />
|
||||
</View>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title={'A Simple List Item Layout'}>
|
||||
<View style={styles.list}>
|
||||
<ListItem imageSource={require('./Thumbnails/like.png')}/>
|
||||
<ListItem imageSource={require('./Thumbnails/poke.png')}/>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
<TextAlignmentExample
|
||||
title={'Default Text Alignment'}
|
||||
description={
|
||||
'In iOS, it depends on active language. ' +
|
||||
'In Android, it depends on the text content.'
|
||||
}
|
||||
style={styles.fontSizeSmall}
|
||||
/>
|
||||
<TextAlignmentExample
|
||||
title={"Using textAlign: 'left'"}
|
||||
description={
|
||||
'In iOS, you must change active language to flip text alignment correctly.' +
|
||||
'In Android, using forceRTL() flips alignment correctly.'
|
||||
}
|
||||
style={[styles.fontSizeSmall, styles.textAlignLeft]}
|
||||
/>
|
||||
<TextAlignmentExample
|
||||
title={"Using textAlign: 'right'"}
|
||||
description={'In iOS/Android, text alignment flips regardless of languages or text content.'}
|
||||
style={[styles.fontSizeSmall, styles.textAlignRight]}
|
||||
/>
|
||||
<UIExplorerBlock title={'Working With Icons'}>
|
||||
<View style={styles.flexDirectionRow}>
|
||||
<View>
|
||||
<Image
|
||||
source={require('./Thumbnails/like.png')}
|
||||
style={styles.image}
|
||||
/>
|
||||
<Text style={styles.fontSizeExtraSmall}>
|
||||
Without directional meaning
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.rightAlignStyle}>
|
||||
<Image
|
||||
source={require('./Thumbnails/poke.png')}
|
||||
style={[styles.image, styles.withRTLStyle]}
|
||||
/>
|
||||
<Text style={styles.fontSizeExtraSmall}>
|
||||
With directional meaning
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock
|
||||
title={'Controlling Animation'}
|
||||
description={'Animation direction according to layout'}
|
||||
>
|
||||
<View Style={styles.view}>
|
||||
<AnimationBlock
|
||||
onPress={this._linearTap.bind(this)}
|
||||
imgStyle={{transform: [{translateX: this.state.linear}, {scaleX: IS_RTL ? -1 : 1}]}}
|
||||
/>
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
</UIExplorerPage>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
_onLayout = (e: Object) => {
|
||||
this.setState({
|
||||
windowWidth: e.nativeEvent.layout.width,
|
||||
});
|
||||
};
|
||||
|
||||
_onDirectionChange = () => {
|
||||
I18nManager.forceRTL(!this.state.isRTL);
|
||||
this.setState({isRTL: !this.state.isRTL});
|
||||
Alert.alert('Reload this page',
|
||||
'Please reload this page to change the UI direction! ' +
|
||||
'All examples in this app will be affected. ' +
|
||||
'Check them out to see what they look like in RTL layout.'
|
||||
);
|
||||
};
|
||||
|
||||
_linearTap = (refName: string, e: Object) => {
|
||||
this.setState({
|
||||
toggleStatus: {
|
||||
...this.state.toggleStatus,
|
||||
[refName]: !this.state.toggleStatus[refName],
|
||||
},
|
||||
});
|
||||
const offset = IMAGE_SIZE[0] / SCALE / 2 + 10;
|
||||
const toMaxDistance =
|
||||
IS_RTL ?
|
||||
-this.state.windowWidth / 2 + offset :
|
||||
this.state.windowWidth / 2 - offset;
|
||||
Animated.timing(this.state.linear, {
|
||||
toValue: this.state.toggleStatus[refName] ? toMaxDistance : 0,
|
||||
duration: 2000,
|
||||
}).start();
|
||||
};
|
||||
|
||||
_onPanResponderGrant = (e: Object, gestureState: Object) => {
|
||||
this.state.pan.stopAnimation(value => {
|
||||
this.state.pan.setOffset(value);
|
||||
});
|
||||
};
|
||||
|
||||
_onPanResponderEnd = (e: Object, gestureState: Object) => {
|
||||
this.state.pan.flattenOffset();
|
||||
Animated.sequence([
|
||||
Animated.decay(this.state.pan, {
|
||||
velocity: {x: gestureState.vx, y: gestureState.vy},
|
||||
deceleration: 0.995,
|
||||
}),
|
||||
Animated.spring(this.state.pan, {toValue: {x: 0, y: 0}}),
|
||||
]).start();
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: '#e9eaed',
|
||||
paddingTop: 15,
|
||||
},
|
||||
directionBox: {
|
||||
flex: 1,
|
||||
backgroundColor: '#f8f8f8',
|
||||
borderWidth: 0.5,
|
||||
borderColor: 'black',
|
||||
},
|
||||
directionText: {
|
||||
padding: 10,
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
switchRowTextView: {
|
||||
flex: 1,
|
||||
marginBottom: 5,
|
||||
marginTop: 5,
|
||||
textAlign: 'center',
|
||||
},
|
||||
switchRowSwitchView: {
|
||||
flex: 3,
|
||||
},
|
||||
rightAlignStyle: {
|
||||
right: 10,
|
||||
position: 'absolute',
|
||||
},
|
||||
list: {
|
||||
height: 120,
|
||||
marginBottom: 5,
|
||||
borderTopWidth: 0.5,
|
||||
borderLeftWidth: 0.5,
|
||||
borderRightWidth: 0.5,
|
||||
borderColor: '#e5e5e5',
|
||||
},
|
||||
row: {
|
||||
height: 60,
|
||||
flexDirection: 'row',
|
||||
borderBottomWidth: 0.5,
|
||||
borderColor: '#e5e5e5',
|
||||
},
|
||||
column1: {
|
||||
width: 60,
|
||||
},
|
||||
column2: {
|
||||
flex: 2.5,
|
||||
padding: 6,
|
||||
},
|
||||
column3: {
|
||||
flex: 1.5,
|
||||
},
|
||||
icon: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
margin: 6,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#e5e5e5',
|
||||
},
|
||||
withRTLStyle: {
|
||||
transform: [{scaleX: IS_RTL ? -1 : 1}],
|
||||
},
|
||||
image: {
|
||||
left: 30,
|
||||
width: 48,
|
||||
height: 48,
|
||||
},
|
||||
img: {
|
||||
width: IMAGE_SIZE[0] / SCALE,
|
||||
height: IMAGE_SIZE[1] / SCALE,
|
||||
},
|
||||
view: {
|
||||
flex: 1,
|
||||
},
|
||||
block: {
|
||||
padding: 10,
|
||||
alignItems: 'center',
|
||||
},
|
||||
smallButton: {
|
||||
top: 18,
|
||||
borderRadius: 5,
|
||||
height: 24,
|
||||
width: 64,
|
||||
backgroundColor: '#e5e5e5',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
fontSizeSmall:{
|
||||
fontSize: 10,
|
||||
},
|
||||
fontSizeExtraSmall:{
|
||||
fontSize: 8,
|
||||
},
|
||||
textAlignLeft: {
|
||||
textAlign: 'left',
|
||||
},
|
||||
textAlignRight: {
|
||||
textAlign: 'right',
|
||||
},
|
||||
textBox: {
|
||||
width: 28,
|
||||
},
|
||||
flexDirectionRow: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RTLExample;
|
|
@ -189,6 +189,10 @@ const APIExamples = [
|
|||
key: 'PointerEventsExample',
|
||||
module: require('./PointerEventsExample'),
|
||||
},
|
||||
{
|
||||
key: 'RTLExample',
|
||||
module: require('./RTLExample'),
|
||||
},
|
||||
{
|
||||
key: 'ShareExample',
|
||||
module: require('./ShareExample'),
|
||||
|
|
|
@ -251,6 +251,10 @@ const APIExamples: Array<UIExplorerExample> = [
|
|||
key: 'RCTRootViewIOSExample',
|
||||
module: require('./RCTRootViewIOSExample'),
|
||||
},
|
||||
{
|
||||
key: 'RTLExample',
|
||||
module: require('./RTLExample'),
|
||||
},
|
||||
{
|
||||
key: 'ShareExample',
|
||||
module: require('./ShareExample'),
|
||||
|
|
|
@ -87,6 +87,7 @@ const ReactNative = {
|
|||
get DatePickerAndroid() { return require('DatePickerAndroid'); },
|
||||
get Dimensions() { return require('Dimensions'); },
|
||||
get Easing() { return require('Easing'); },
|
||||
get I18nManager() { return require('I18nManager'); },
|
||||
get ImagePickerIOS() { return require('ImagePickerIOS'); },
|
||||
get IntentAndroid() { return require('IntentAndroid'); },
|
||||
get InteractionManager() { return require('InteractionManager'); },
|
||||
|
|
|
@ -99,6 +99,7 @@ var ReactNative = {
|
|||
DatePickerAndroid: require('DatePickerAndroid'),
|
||||
Dimensions: require('Dimensions'),
|
||||
Easing: require('Easing'),
|
||||
I18nManager: require('I18nManager'),
|
||||
ImagePickerIOS: require('ImagePickerIOS'),
|
||||
IntentAndroid: require('IntentAndroid'),
|
||||
InteractionManager: require('InteractionManager'),
|
||||
|
|
Loading…
Reference in New Issue