I'm using Video from expo-av to display my videos. My goal is to display the video depending on the Orientation of the device of the user. I'm using ScreenOrientation from expo-screen-orientation so i can detect the rotation using the addOrientationChangeListener function.
I tried my code below but i can't detect the change of the orientation. Any Help of how can i achieve my goal or what's wrong in my code?
import React, { Component } from 'react';
import {
StyleSheet,
View,
TouchableOpacity,
Image,
Text,
Alert,
ScrollView,
Dimensions
} from 'react-native';
import { Video } from 'expo-av';
import * as ScreenOrientation from 'expo-screen-orientation';
import NavigationHelper from '../../../../Helpers/NavigationHelper';
export default class VideoScreen extends Component {
constructor(props) {
super(props);
/* enum Orientation {
UNKNOWN = 0,
PORTRAIT_UP = 1,
PORTRAIT_DOWN = 2,
LANDSCAPE_LEFT = 3,
LANDSCAPE_RIGHT = 4
} */
this.state = {
orientation: 1,
};
}
async componentDidMount() {
await this.detectOrientation();
this.subscription = ScreenOrientation.addOrientationChangeListener(this.onOrientationChange);
/* if (ScreenOrientation.Orientation.LANDSCAPE) {
this.changeScreenLandscapeOrientation();
} */
}
async componentWillUnmount() {
await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT);
ScreenOrientation.removeOrientationChangeListener(this.subscription);
// this.changeScreenPortraitOrientation();
}
onOrientationChange = async (orientation) => {
console.log('orientation changed');
if (orientation === 3 || orientation === 4) {
await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE);
} else {
await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT);
}
this.setState({ orientation });
};
detectOrientation= async () => {
let orientation = await ScreenOrientation.getOrientationAsync();
const screen = Dimensions.get('screen');
if (orientation === 0) {
orientation = screen.width > screen.height ? ScreenOrientation.Orientation.LANDSCAPE : ScreenOrientation.Orientation.PORTRAIT;
}
this.setState({ orientation });
console.log(orientation);
};
render() {
const { route } = this.props;
const { videoUri } = route.params;
if (!videoUri) {
NavigationHelper.back();
}
return (
<ScrollView style={styles.container}>
<Video
source={{ uri: videoUri }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode={Video.RESIZE_MODE_CONTAIN}
shouldPlay
isLooping
useNativeControls
style={{ width: 300, height: 300, alignSelf: 'center' }}
orientationChange={this.onOrientationChange}
/>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000000',
flexDirection: 'column'
},
});
Look at the library method getOrientationAsync()
export declare function getOrientationAsync(): Promise<Orientation>;
The orientation definition is
export declare enum Orientation {
UNKNOWN = 0,
PORTRAIT_UP = 1,
PORTRAIT_DOWN = 2,
LANDSCAPE_LEFT = 3,
LANDSCAPE_RIGHT = 4
}
So, it already returns the integer that refers to the correct orientation. Maybe what you want to do is just remove the brackets between the orientation:
let orientation = await ScreenOrientation.getOrientationAsync();
Related
hi everyone i'm just learning react native and i have a problem. I cannot send the status from the parent screen (Parent.js) to the child screen (RecyclerViewChildPage.js which is a recyclerview). Now the child screen is a recyclerView showing the list of comments, but it's as if the parent screen can't send anything to the child screen. My code is:
Parent .js
import React, { Component} from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import Utils from './Utils';
import RecyclerViewChildPage from './RecyclerViewChildPage ';
export default class Parent extends Component {
static sid=""
static navigation={}
constructor(){
super();
this.state={
comment_state: [],
datetime: []
}
}
async getPosts(){
var sid=this.props.route.params.value_sid
var did=this.props.route.params.value_did
const utils=new Utils();
const responseJson = await utils.getPost(sid,did)
const comment = (responseJson?.posts ?? []).map((data) => data.comment)
this.setState({comment_state:comment})
}
componentDidMount(){
this.getPosts()
}
render(){
return (
<RecyclerViewChildPage
comment={this.state.comment_state}
/>
)
}
}
And child screen is:
RecyclerViewChildPage .js
import React, {Component} from 'react';
import { StyleSheet, View, Dimensions, Text } from 'react-native';
import { RecyclerListView, DataProvider, LayoutProvider } from 'recyclerlistview';
const SCREEN_WIDTH = Dimensions.get('window').width;
export default class RecyclerViewChildPage extends Component {
constructor(props) {
super(props);
const fakeData = [];
for(i = 0; i < 100; i+= 1) {
fakeData.push({
type: 'NORMAL',
item: {
id: i,
comment: this.props.comment
},
});
}
this.state = {
list: new DataProvider((r1, r2) => r1 !== r2).cloneWithRows(fakeData),
};
this.layoutProvider = new LayoutProvider((i) => {
return this.state.list.getDataForIndex(i).type;
}, (type, dim) => {
switch (type) {
case 'NORMAL':
dim.width = SCREEN_WIDTH;
dim.height = 100;
break;
default:
dim.width = 0;
dim.height = 0;
break;
};
})
}
rowRenderer = (type, data) => {
const { comment} = data.item;
return (
<View style={styles.listItem}>
<View style={styles.body}>
<Text style={styles.comment}>{comment}</Text>
</View>
</View>
)
}
render() {
return (
<View style={styles.container}>
<RecyclerListView
style={{flex: 1}}
rowRenderer={this.rowRenderer}
dataProvider={this.state.list}
layoutProvider={this.layoutProvider}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FFF',
minHeight: 1,
minWidth: 1,
},
body: {
marginLeft: 10,
marginRight: 10,
maxWidth: SCREEN_WIDTH - (80 + 10 + 20),
},
comment: {
fontSize: 14,
opacity: 0.5,
},
listItem: {
flexDirection: 'row',
margin: 10,
}
});
I can't switch the status from the parent screen to the child screen, why?
I'm a bit new to React Native programming, and I'm working on implementing an autoscroll feature for PDFs. For example, in some cases, I want to automatically scroll a PDF down x pages and then scroll at a desired speed. I followed this tutorial here here which works for just normal data, but when I used a object from react-native-pdf, it does not seem to scroll anymore. I'm wrapping the PDF object inside a ScrollView and can confirm that the scrolling code is being called. Can anyone suggest a solution or explain why this does not work with the PDF? Thanks so much!
I've also attached my code below if that helps. Currently, the PDF displays but is not autoscrolling at all.
import React from 'react';
import {StyleSheet, Dimensions, View, ScrollView} from 'react-native';
import Pdf from 'react-native-pdf';
export default class PDFScroll extends React.Component {
constructor(props) {
super(props);
this.state = {
currentPosition: 0,
};
this.scrolling = this.scrolling.bind(this);
}
componentDidMount(){
this.activeInterval = setInterval(this.scrolling, 100);
}
componentWillUnmount(){
clearInterval(this.activeInterval);
}
scrolling() {
position = this.state.currentPosition + 50;
this.pdf.scrollTo({ x: position, animated: true });
// After position passes this value, snaps back to beginning
let maxOffset = 2000;
// Set animation to repeat at end of scroll
if (this.state.currentPosition > maxOffset) {
this.pdf.scrollTo({ x: 0, animated: false })
this.setState({ currentPosition: 0 });
}
else {
this.setState({ currentPosition: position });
}
}
render() {
const source = {
uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf',
cache: true,
};
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollview}
horizontal={false}
bounces={true}
ref={(ref) => this.pdf = ref}
>
{
<Pdf
source={source}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`number of pages: ${numberOfPages}`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`current page: ${page}`);
}}
onError={error => {
console.log(error);
}}
onPressLink={uri => {
console.log(`Link presse: ${uri}`);
}}
style={styles.pdf}
/>
}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: 25,
},
pdf: {
flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
});
I wrote this code for get the signature of a person:
import * as ExpoPixi from 'expo-pixi';
import React, { Component } from 'react';
import { Platform, AppState, StyleSheet, Text, View } from 'react-native';
const isAndroid = Platform.OS === 'android';
function uuidv4() {
// https://stackoverflow.com/a/2117523/4047926
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
export default class App extends Component {
state = {
signature: null,
appState: AppState.currentState,
};
handleAppStateChangeAsync = nextAppState => {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
if (isAndroid && this.sketch) {
this.setState({ appState: nextAppState, id: uuidv4(), lines: this.sketch.lines });
return;
}
}
this.setState({ appState: nextAppState });
};
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChangeAsync);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChangeAsync);
}
onChange = async () => {
const { uri } = await this.sketch.takeSnapshotAsync();
this.setState({
signature: { uri },
}, () => console.log(this.state.signature));
}
render() {
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<View style={{flex: 1, left: '5%'}}>
<ExpoPixi.Signature
ref={signature => (this.sketch = signature)}
style={styles.pad}
strokeColor={'black'}
strokeAlpha={0.5}
onChange={this.onChange}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
pad: {
flex: 1,
width: '90%',
borderWidth: 0.6,
borderColor: '#b3b3b5',
borderRadius: 10,
backgroundColor: 'white'
},
});
Running this simple code that is inspired on this library example, I notice that the borderRadius is ignored (the corner of the View are missing) and when I try to write the signature the app crash.
A side note: is it possible to get a base64-encoded version of the pad content instead of the uri?
I am trying to animate border color in React Native, but animation doesn't work. Border color doesn't have ORIGINAL_COLOR = '#a0a0a0' neither SUCCESS_COLOR = '#008FEB', it is black. How can I make default color ORIGINAL_COLOR = '#a0a0a0' if keyboard is hidden and SUCCESS_COLOR = '#008FEB' when keyboard shows up?
const styles = StyleSheet.create({
inputContainer: {
borderBottomWidth: 1,
},
});
<Input
containerStyle={styles.inputContainer}
underlineColorAndroid="transparent"
/>;
Input.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { TextInput, Text, View, Animated, Keyboard } from 'react-native';
import styles from './styles';
const SUCCESS_COLOR = '#008FEB';
const ORIGINAL_COLOR = '#a0a0a0';
export default class Input extends Component {
constructor(props) {
super(props);
this.color = new Animated.Value(ORIGINAL_COLOR);
}
componentWillMount () {
this.keyboardWillShowSub = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
this.keyboardWillHideSub = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
}
componentWillUnmount() {
this.keyboardWillShowSub.remove();
this.keyboardWillHideSub.remove();
}
keyboardWillShow = (event) => {
console.log(SUCCESS_COLOR);
Animated.timing(this.color, {
duration: event.duration,
toValue: SUCCESS_COLOR,
}).start();
};
keyboardWillHide = (event) => {
console.log(ORIGINAL_COLOR);
Animated.timing(this.color, {
duration: event.duration,
toValue: ORIGINAL_COLOR,
}).start();
};
render() {
const {
value,
} = this.props;
return (
<Animated.View style={[styles.containerStyle, { borderBottomColor: this.color }]}>
<TextInput
ref="input"
{...this.props}
value={value}
/>
</Animated.View>
);
}
}
Here you go: https://snack.expo.io/#zvona/interpolation-of-color
The key is to use interpolate to change the number value into rgb value:
let borderBottomColor = this.color.interpolate({
inputRange: [0, 1],
outputRange: [ORIGINAL_COLOR, SUCCESS_COLOR]
});
I would like to call a function at the end of the function scrollTo called like that :
scrollTo({y: 0, animated: true})
but by default this function doesn't have a second parameter.
So how can i handle the end of the scroll animation to trigger an other function ?
You can use onMomentumScrollEnd as mentioned in this issue
However if you want more control over your scroll state you can implement smth like this
import React from 'react';
import { StyleSheet, Text, View, ScrollView, Button } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollView
style={{ marginVertical: 100 }}
ref={this.refScrollView}
onScroll={this.onScroll}
>
<Text style={{ fontSize: 20 }}>
A lot of text here...
</Text>
</ScrollView>
<Button title="Scroll Text" onPress={this.scroll} />
</View>
);
}
componentDidMount() {
this.scrollY = 0;
}
onScroll = ({ nativeEvent }) => {
const { contentOffset } = nativeEvent;
this.scrollY = contentOffset.y;
if (contentOffset.y === this.onScrollEndCallbackTargetOffset) {
this.onScrollEnd()
}
}
onScrollEnd = () => {
alert('Text was scrolled')
}
refScrollView = (scrollView) => {
this.scrollView = scrollView;
}
scroll = () => {
const newScrollY = this.scrollY + 100;
this.scrollView.scrollTo({ y: newScrollY, animated: true });
this.onScrollEndCallbackTargetOffset = newScrollY;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
padding: 20,
},
});