I am creating an application for android and ios in react-native(0.57.7) and using react-native-video to play videos uploaded into vimeo. After integrate react video plugin, tested in both device. In ios it works perfectly but in android, I am not able to play video in full-screen mode. Here is my code for Android:
import React, { PureComponent } from 'react';
import {
View,
Text,
Image,
ImageBackground,
StyleSheet,
SafeAreaView,
TouchableOpacity,
ActivityIndicator
} from 'react-native';
import PropTypes from 'prop-types'
import Video from "react-native-video";
import Orientation from 'react-native-orientation-locker';
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from '../components/Resposive';
import RF from "react-native-responsive-fontsize"
export default class Videoplayer extends PureComponent {
constructor(props){
super(props);
this.state = {
loading: true,
videoFileArr:[],
showPlayer:false,
playing:false
}
}
componentDidMount() {
Orientation.lockToLandscape();
this.fetchVimeoVideo();
}
componentWillUnmount() {
Orientation.lockToPortrait();
}
goToHome(){
Orientation.lockToPortrait();
this.props.navigation.goBack();
}
fetchVimeoVideo = async () => {
await this.setState({ loading: true });
const { navigation } = this.props;
const jsonReceived = navigation.getParam('item', {})
const url = "https://api.vimeo.com/me/videos/" + jsonReceived.video_link
console.log(url)
const response = await fetch(
url, {
method: "get",
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization:"Bearer f9e937d64037e657addcf088f28e6cb5"
}
});
const jsonResponse = await response.json();
const { files} = jsonResponse;
if (response.status != 200) {
alert(response.status)
}
console.log(files)
await this.setState({ videoFileArr:files, loading: false });
};
renderOptions = () => {
if (this.state.loading === true) {
return (
<View style={{
flex: 1,
alignItems: "center",
justifyContent: "center"
}}>
<ActivityIndicator size="large" color="#00ff00" />
<Text style={{ fontFamily: "Futura Std", fontSize: RF(3.0), fontWeight: "900", color: "#244E25", textAlign: "center" }}>Please wait while we are loading questions for you</Text>
</View>
)
}else if (this.state.videoFileArr.length> 0 && this.state.playing === false) {
const { navigation } = this.props;
const jsonReceived = navigation.getParam('item', {})
return(
<ImageBackground style={{width:"100%",height:"100%",alignItems:"center",justifyContent:"center"}} source={{uri:jsonReceived.video_banner}}>
<TouchableOpacity
onPress={() => {
this.setState({playing:true})
}}
>
<Image source={require("../assets/Common/Play/playIcon.png")}/>
</TouchableOpacity>
</ImageBackground>
)
} else if (this.state.videoFileArr.length > 0 && this.state.playing === true) {
return (
<View style={styles.container}>
<Video source={{ uri:this.state.videoFileArr[0].link}} // Can be a URL or a local file.
ref={ ref =>
this.player = ref
} // Store reference
onBuffer={this.onBuffer} // Callback when remote video is buffering
onError={this.videoError} // Callback when video cannot be loaded
style={styles.backgroundVideo}
controls={true}
paused={false}
fullscreen={true}
/>
</View>
)
}
}
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1, overflow: "hidden" }}>
<View style={{ flex: 1, backgroundColor: "green" }}>
{this.renderOptions()}
</View>
{/* top navigationBar */}
<View
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
width: "100%",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
height: 80,
backgroundColor: null
}}
>
<TouchableOpacity onPress={
()=>this.goToHome()
}>
<Image style={{ margin: 8 }} source={require("../assets/Common/goBack/goBack.png")} />
</TouchableOpacity>
<TouchableOpacity>
<Image style={{ margin: 8 }} source={require("../assets/Common/Star/starOff.png")} />
</TouchableOpacity>
</View>
</View>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container:{ flex: 1, justifyContent: "center"},
backgroundVideo: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
});
and this is the output screen where I can not play video in full screen:
Please help, What I'm doing wrong ?
I have solved fullscreen of video frame just adding resizeMode on Video component:
<Video source={{ uri:this.state.videoFileArr[0].link}} // Can be a URL or a local file.
ref={ ref =>
this.player = ref
} // Store reference
onBuffer={this.onBuffer} // Callback when remote video is buffering
onError={this.videoError} // Callback when video cannot be loaded
style={styles.backgroundVideo}
controls={true}
paused={false}
fullscreen={true}
resizeMode="cover"
/>
I was struggling with the same problem couple of days ago but I made it work for me in android. I hope this will help you also.
You will need to install some other package as well that is
1. react-native-video-controls
2. react-native-orientation
now In your Screen where the video will be played.
import React, { Component } from 'react'
import {
Text,
StyleSheet,
StatusBar,
Dimensions,
Alert,
Modal,
BackHandler,
TouchableOpacity,
ToastAndroid,
} from 'react-native'
import { Container, View, Button, Icon, List, ListItem } from 'native-base';
import Video from 'react-native-video';
import Orientation from 'react-native-orientation';
const sample = require('../assets/demo.mp4');
export default class Player extends Component {
constructor(props) {
super(props);
this.onLoad = this.onLoad.bind(this);
this.onProgress = this.onProgress.bind(this);
}
state = {
rate: 1,
volume: 1,
muted: false,
resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
active: false,
modalVisible: false,
fullScreen: true,
};
onLoad(data) {
this.setState({ duration: data.duration });
}
onProgress(data) {
this.setState({ currentTime: data.currentTime });
}
getCurrentTimePercentage() {
if (this.state.currentTime > 0) {
return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
} else {
return 0;
}
}
renderRateControl(rate) {
const isSelected = (this.state.rate == rate);
return (
<ListItem>
<TouchableOpacity onPress={() => { this.setState({ rate: rate }) }}>
<Text style={{ fontWeight: isSelected ? "bold" : "normal" }}>
{rate}x
</Text>
</TouchableOpacity>
</ListItem>
)
}
renderResizeModeControl(resizeMode) {
const isSelected = (this.state.resizeMode == resizeMode);
return (
<TouchableOpacity onPress={() => { this.setState({ resizeMode: resizeMode })
}}>
<Text style={[styles.controlOption, { fontWeight: isSelected ? "bold" :
"normal" }]}>
{resizeMode}
</Text>
</TouchableOpacity>
)
}
setModalVisible = (visible) => {
this.setState({ modalVisible: visible });
}
fullScreen = () => {
Orientation.getOrientation((err, orientation) => {
if (orientation == 'LANDSCAPE') {
Orientation.lockToPortrait();
} else {
Orientation.lockToLandscape();
}
});
}
backAction = () => {
Orientation.getOrientation((err, orientation) => {
if (orientation == 'LANDSCAPE') {
Orientation.lockToPortrait();
}
});
};
componentDidMount() {
this.backHandler = BackHandler.addEventListener(
"hardwareBackPress",
this.backAction
);
}
componentWillUnmount() {
this.backHandler.remove();
}
render() {
const { modalVisible, paused } = this.state
const url = `https://www.sample-
videos.com/video/mp4/720/big_buck_bunny_720p_10mb.mp4`;
const flexCompleted = this.getCurrentTimePercentage() * 100;
const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
return (
<View style={styles.container}>
<StatusBar hidden={true} />
<Video source={sample}
style={styles.fullScreen}
rate={this.state.rate}
paused={this.state.paused}
volume={this.state.volume}
muted={this.state.muted}
resizeMode={this.state.resizeMode}
onLoad={this.onLoad}
onProgress={this.onProgress}
onEnd={() => { alert('Done!') }}
controls
repeat={true} />
<View style={[{ left: 0 }, styles.rateControl]}>
<Button
transparent
onPress={() => {
this.fullScreen();
}}
>
<Icon type="FontAwesome5" name="compress" style={{ color: "#fff",
fontSize: 15 }} />
</Button>
</View>
<View style={styles.rateControl}>
<Button
transparent
onPress={() => {
this.setModalVisible(true);
}}
>
<Icon type="FontAwesome5" name="ellipsis-v" style={{ color:
"#fff", fontSize: 15 }} />
</Button>
</View>
{/* <View style={styles.controls}>
<View style={styles.generalControls}>
<View style={styles.resizeModeControl}>
{this.renderResizeModeControl('cover')}
{this.renderResizeModeControl('contain')}
{this.renderResizeModeControl('stretch')}
</View>
</View>
<View style={styles.trackingControls}>
<View style={styles.progress}>
<View style={[styles.innerProgressCompleted, { flex: flexCompleted }]} />
<View style={[styles.innerProgressRemaining, { flex: flexRemaining }]} />
</View>
</View>
</View> */}
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<View style={styles.closeModal}>
<Button
transparent
onPress={() => { this.setModalVisible(!modalVisible);
}}
>
<Icon name="close" />
</Button>
</View>
<View>
<Text style={{ textAlign: 'center', fontWeight: 'bold'
}}>Play Rate</Text>
<List style={{ flexDirection: 'row', justifyContent:
'space-between', alignItems: 'center' }}>
{this.renderRateControl(0.25)}
{this.renderRateControl(0.5)}
{this.renderRateControl(1.0)}
{this.renderRateControl(1.5)}
{this.renderRateControl(2.0)}
</List>
</View>
</View>
</View>
</Modal>
</View >
)
}
}
const styles = StyleSheet.create({
backgroundVideo: {
// position: 'absolute',
// top: 0,
// left: 0,
// bottom: 0,
// right: 0,
width: Dimensions.get('window').width,
height: Dimensions.get('window').width * .6,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
fullScreen: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
controls: {
backgroundColor: "transparent",
borderRadius: 5,
position: 'absolute',
bottom: 20,
left: 20,
right: 20,
},
progress: {
flex: 1,
flexDirection: 'row',
borderRadius: 3,
overflow: 'hidden',
},
innerProgressCompleted: {
height: 20,
backgroundColor: '#cccccc',
},
innerProgressRemaining: {
height: 20,
backgroundColor: '#2C2C2C',
},
generalControls: {
flex: 1,
// flexDirection: 'row',
borderRadius: 4,
overflow: 'hidden',
paddingBottom: 10,
},
rateControl: {
flexDirection: 'row',
position: 'absolute',
top: 10,
right: 10
},
volumeControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
resizeModeControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
controlOption: {
alignSelf: 'center',
fontSize: 11,
color: "white",
paddingLeft: 2,
paddingRight: 2,
lineHeight: 12,
},
centeredView: {
flex: 1,
marginTop: '22%'
},
modalView: {
width: '100%',
padding: '5%',
backgroundColor: "white",
position: 'absolute',
bottom: 10,
},
openButton: {
backgroundColor: "#F194FF",
borderRadius: 20,
padding: 10,
elevation: 2
},
closeModal: {
alignItems: 'flex-end',
margin: -10
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
modalText: {
marginBottom: 15,
textAlign: "center"
}
});
I hope this will help you.
Most of suggestion involves adding additional libraries to achieve fullscreen in react-native-vide for android. Its not really needed.
What we need is set the height and width of to full screen to achieve this. we need to use variable instead of fixed value then setState to refresh the view.
Below is the sample typescript code that works for react-native-video fullscreen:
import React, {Component} from 'react';
import {
View,
StyleSheet,
TouchableWithoutFeedback,
Dimensions,
} from 'react-native';
import Video from 'react-native-video';
import Icon from 'react-native-vector-icons/FontAwesome';
import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons';
interface Props {}
interface States {
paused: boolean;
inFullScreen: boolean;
}
export default class Sandbox extends Component<Props, States> {
player: any;
videoStyle: {minWidth: number; minHeight: number};
constructor(props: Props) {
super(props);
this.state = {
paused: true,
inFullScreen: false,
};
this.videoStyle = {minWidth: 400, minHeight: 400};
}
render() {
return (
<View style={{height: 400, width: 400}}>
<Video
source={{
uri:
'https://www.radiantmediaplayer.com/media/big-buck-bunny-360p.mp4',
}} // Can be a URL or a local file.
ref={(ref: any) => {
this.player = ref;
}} // Store reference
controls={false}
paused={this.state.paused}
resizeMode={'cover'}
style={this.videoStyle}
/>
<View style={styles.controls}>
<TouchableWithoutFeedback
onPress={() => {
this.setState({paused: !this.state.paused});
}}>
<Icon name={'play'} size={30} color="#FFF" />
</TouchableWithoutFeedback>
<TouchableWithoutFeedback
onPress={() => {
if (!this.state.inFullScreen) {
//Orientation.lockToLandscape();
this.videoStyle = {
minHeight: Dimensions.get('window').height,
minWidth: Dimensions.get('window').width,
};
} else {
this.videoStyle = {
minHeight: 400,
minWidth: 400,
};
}
this.setState({inFullScreen: !this.state.inFullScreen});
}}>
<MaterialIcon name={'fullscreen'} size={30} color="#FFF" />
</TouchableWithoutFeedback>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
controls: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
height: 48,
top: 20,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
paddingHorizontal: 10,
},
});
As #Selva answered we can use variables for video sizes i.e width & height and make it occupy full screen and use a stack to place the video in a stack screen above the current screen and pop it when needed. Even if it's in a flat list.
Had same issue fix it by removing the wrapping and setting just the height to the player, no other library needed and no need to manage the orientation.
<Video source={{uri: this.props.videoData.uri}}
onEnd={this.onVideoEnd}
style={styles.player}
controls={true} />
<View
onStartShouldSetResponder={() => setPaused(!paused)}
style={{
marginHorizontal: 10,
backgroundColor: "black",
position: "relative",
transform: [{ rotate: "90deg" }],
// justifyContent:'center',
// alignItems:'center'
}}
>
<Video
onEnd={onEnd}
onLoad={onLoad}
onLoadStart={onLoadStart}
posterResizeMode={"cover"}
onProgress={onProgress}
paused={paused}
ref={(ref) => (videoPlayer.current = ref)}
resizeMode={'stretch'}
source={{
uri: "url",
}}
style={{
...styles.backgroundVideo,
height: width,
aspectRatio:2
// width: "100%"
// alignSelf:'center'
// transform: [{ rotate: '90deg'}]
}}
/>
just give it a width of
width:'100%'
Related
On Android elements wrapped in BlurVIew don't positioning right.
It works on iOS devices fine. But on Android, elements wrapped in <BlurView>{children}</BlurView> run into each other. Screenshot is below
Sometimes when I change something in styles in dev mode, it works correctly, but when I build apk, bug appears again.
How can I fix it on Android?
Code
const BottomNavigationTabs: React.FC<BottomTabBarProps> = ({
descriptors,
state,
navigation,
}) => {
const focusedOptions = descriptors[state.routes[state.index].key].options;
return (
<>
<BlurView blurType="light"
blurAmount={15} style={{ height: 85, width: '100%', position: 'absolute', bottom: 0, }}>
<View style={{ display: 'flex', flexDirection: 'row', position: 'absolute', bottom: 0, justifyContent: 'space-between' }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const focusedColor = isFocused ? colors.text1 : colorsOld.black;
//Weird snippet, to render passed icon just call function with any return value, then just set color
const icon =
options.tabBarIcon &&
React.cloneElement(
//#ts-ignore
options.tabBarIcon((props: any) => props),
{ color: focusedColor }
);
const onPress = () => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: "tabLongPress",
target: route.key,
});
};
const tabBtn = (
<TouchableOpacity
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
style={styles.tabButton}
onLongPress={onLongPress}
activeOpacity={0.7}
key={route.key}
>
<View style={styles.tabItem}>
<View style={styles.tabItemIcon}>{icon}</View>
<Text style={{ ...styles.tabItemLabel, color: focusedColor }}>
{label}
</Text>
</View>
</TouchableOpacity>
);
return tabBtn;
})}
</View>
</BlurView>
</>
);
};
const styles = StyleSheet.create({
container: {
alignItems: "center",
justifyContent: "center",
paddingTop: 9,
paddingBottom: 15,
},
tabButton: {
paddingTop: 8,
paddingBottom: 15,
paddingHorizontal: 10,
borderRadius: 10,
zIndex: 10000
},
tabsContainer: {
backgroundColor: colors.secondaryBg(0.5),
width: "100%",
left: 0,
bottom: 0,
zIndex: 999,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-around",
},
tabItem: {
justifyContent: "center",
alignItems: "center",
},
tabItemIcon: {
marginBottom: 6,
},
tabItemLabel: {
fontSize: 12,
fontFamily: "Inter-Medium",
},
});
Found a solution here https://github.com/Kureev/react-native-blur/issues/483#issuecomment-1199210714.
Solution is to not set to <BlurView> position: absolute and to not wrapping anything with it. In my case looks like:
import React from "react";
import {
Text,
View,
ImageBackground,
TouchableOpacity,
StyleSheet,
} from "react-native";
import { BlurView } from "#react-native-community/blur";
import { BottomTabBarProps } from "#react-navigation/bottom-tabs";
import colorsOld from "src/theme/colorsOld";
import colors from "src/theme/colors";
const BottomNavigationTabs: React.FC<BottomTabBarProps> = ({
descriptors,
state,
navigation,
}) => {
const focusedOptions = descriptors[state.routes[state.index].key].options;
return (
<View
style={{
display: "flex",
flexDirection: "row",
backgroundColor: colors.secondaryBg(0.5),
position: "absolute",
bottom: 0,
justifyContent: "space-between",
}}
>
<BlurView
blurType="light"
blurAmount={15}
style={{ height: 85, width: "100%", bottom: 0 }}
/>
<View style={styles.tabsContainer}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const focusedColor = isFocused ? colors.text1 : colorsOld.black;
//Weird snippet, to render passed icon just call function with any return value, then just set color
const icon =
options.tabBarIcon &&
React.cloneElement(
//#ts-ignore
options.tabBarIcon((props: any) => props),
{ color: focusedColor }
);
const onPress = () => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: "tabLongPress",
target: route.key,
});
};
const tabBtn = (
<TouchableOpacity
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
style={styles.tabButton}
onLongPress={onLongPress}
activeOpacity={0.7}
key={route.key}
>
<View style={styles.tabItem}>
<View style={styles.tabItemIcon}>{icon}</View>
<Text style={{ ...styles.tabItemLabel, color: focusedColor }}>
{label}
</Text>
</View>
</TouchableOpacity>
);
return tabBtn;
})}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
alignItems: "center",
justifyContent: "center",
paddingTop: 9,
paddingBottom: 15,
},
tabButton: {
paddingTop: 8,
paddingBottom: 15,
paddingHorizontal: 10,
borderRadius: 10,
zIndex: 10000,
},
tabsContainer: {
width: "100%",
left: 0,
bottom: 0,
zIndex: 999,
position: 'absolute',
flexDirection: "row",
alignItems: "center",
justifyContent: "space-around",
},
tabItem: {
justifyContent: "center",
alignItems: "center",
},
tabItemIcon: {
marginBottom: 6,
},
tabItemLabel: {
fontSize: 12,
fontFamily: "Inter-Medium",
},
});
export default BottomNavigationTabs;
I have been trying to get the blur effect to work on Android for a long time.
I tried to solve it using the viewRef reference system but it doesn't work right. Can somebody help me?
The sample page I wrote for Android is as follows;
import React, { useCallback, useEffect, useState, useRef } from 'react';
import { Image, StyleSheet, Text, TouchableOpacity, View, findNodeHandle, InteractionManager } from 'react-native';
import { BlurView } from '#react-native-community/blur';
const AndroidPreviewScreen = ({ route, navigation }) => {
const { speed, brightness, selectedDevice, selectedAnimationId, selectedUserTheme, selectedThemeId, selectedEqAnimation, selectedColors } = route.params;
const selectedAnimation = selectedAnimationId && animationOptions.find(o => o.id === selectedAnimationId);
const selectedTheme = selectedThemeId && themeOptions.find(o => o.id === selectedThemeId);
const [isVisible, setIsVisible] = useState(false);
const [viewRef, setViewRef] = useState(null);
const blurRef = useRef();
useEffect(() => {
setTimeout(() => {
setIsVisible(true);
}, 50);
}, [])
const onBack = useCallback(() => {
setIsVisible(false);
setTimeout(() => {
vibrateLight();
navigation.goBack();
}, 5);
}, []);
return (
<View style={styles.container} >
<TouchableOpacity style={styles.closeBtn} onPress={onBack} hitSlop={hitSlop.mid}>
<FontAwesome5Icon name="times" color={colors.powerCustomBg} size={20} style={styles.closeIcon} />
</TouchableOpacity>
{isVisible && <View style={styles.previewImageContainer}>
{selectedDevice && !selectedDevice.isOn && <View style={styles.offContainer}>
<FontAwesome5Icon name={'info-circle'} size={20} color={colors.powerBtnOn} />
<Text style={styles.offText}>Off</Text>
</View>}
<View style={[styles.colorMaskContainer]}
ref={n => {
if (n && viewRef === null) {
setViewRef(findNodeHandle(n))
}
}}
collapsable={false}
>
// I want to blur this section.
</View>
{console.log("viewRef : : ", viewRef)}
{viewRef && <BlurView
style={styles.blur}
viewRef={viewRef}
blurType={"light"}
blurRadius={20}
blurAmount={20}
downsampleFactor={5}
overlayColor={"light"}
// reducedTransparencyFallbackColor="white"
/>
}
<Image resizeMethod="auto" resizeMode="cover" source={{ uri: 'asset:/images/images/imageMy.webp' }} style={[styles.previewImage]} />
</View>}
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.black,
zIndex: 9999999
},
closeBtn: {
flexDirection: 'row',
position: 'absolute',
right: 15,
top: deviceHeight * 0.13 - 75,
zIndex: 9999,
backgroundColor: colors.noThemeBg,
width: 36,
height: 36,
borderRadius: 20,
alignItems: 'center',
alignContent: 'center',
justifyContent: 'center'
},
closeIcon: {
textAlign: 'center'
},
previewImageContainer: {
flex: 1,
width: '100%',
alignSelf: 'center',
flexDirection: 'column',
overflow: 'hidden',
borderColor: colors.mainBgMid,
},
offContainer: {
position: 'absolute',
top: 20,
flexDirection: 'row',
alignSelf: 'center',
zIndex: 99
},
offText: {
color: colors.powerBtnOn,
fontFamily: 'Montserrat-SemiBold',
fontSize: 14,
lineHeight: 16,
alignSelf: 'center',
marginLeft: 10
},
colorMaskContainer: {
position: 'absolute',
top: '15%',
height: '65%',
width: '100%',
backgroundColor: "#000",
},
colorMask: {
position: 'absolute',
alignSelf: 'center',
width: '100%',
backgroundColor: "#000",
},
blur: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
previewImage: {
position: 'absolute',
height: '100%',
width: '100%',
}
});
export default AndroidPreviewScreen;
I want to blur where I try to refer to viewRef. The reference value I gave in BlurView points to that View.
import React, { Component } from 'react'
import { View, ScrollView, Text, Switch,Alert, TouchableOpacity, StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import { NavigationActions } from 'react-navigation'
import PinInput from 'react-native-pin-input';
import { VALER_PURPLE, VALER_BACKGROUND, VALER_LABELTEXT, VALER_CELLBORDER } from '../../Assets/GlobalStyle'
import { ButtonCell } from '../Templates/ButtonCell'
import TouchIDScan from 'react-native-touch-id'; **strong text**
class TouchIDPIN extends Component {
static navigationOptions = {
title: 'Touch ID & PIN',
headerStyle: { backgroundColor: VALER_PURPLE },
headerTintColor: 'white',
headerTitleStyle: { alignSelf: 'center' },
headerRight: (<View></View>)
};
state = {
PIN: false,
touchID: false,
}
componentWillMount() {
if (this.props.navigation.state.params && this.props.navigation.state.params.radioEnable) {
this.setState({ PIN: this.props.navigation.state.params.radioEnable });
}
else {
this.setState({ PIN: this.props.user && this.props.user.enabledPin ? this.props.user.enabledPin : false })
}
}
changePin = () => {
if (this.state.PIN) {
this.props.navigation.navigate('ChangePin');
} else {
alert("Please Enable Pin first");
}
}
togglePin = () => {
if (this.props.user && this.props.user.enabledPin == false) {
this.setState({ PIN: false });
this.props.navigation.navigate('ChangePin');
}
else {
this.setState({ PIN: !this.state.PIN });
}
}
_pressHandler() {
// alert("")
TouchIDScan.authenticate('to demo this react-native component')
.then(success => {
Alert.alert('Authenticated Successfully');
})
.catch(error => {
console.log('Authentication Failed',error);
});
}
toggleTouchId() {
TouchIDScan.isSupported().then((res) => {
console.log('TouchID is supported.');
}).catch((err) => {
console.log('TouchID is not supported.',err.message);
})
}
componentWillReceiveProps(nextProps) {
this.setState({ PIN: nextProps.user && nextProps.user.enabledPin ? nextProps.user.enabledPin : false })
}
render() {
return (
<ScrollView style={{ flex: 1, backgroundColor: VALER_BACKGROUND }}>
<Text style={{ color: VALER_LABELTEXT, marginTop: 10, paddingLeft: 10, fontSize: 13 }}>Security Options</Text>
<View style={{ height: 1, backgroundColor: VALER_CELLBORDER }} />
<View style={{ marginTop: 3, paddingLeft: 10, height: 90, backgroundColor: 'white' }}>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ flex: 1, fontSize: 17 }}>PIN</Text>
<View style={{ flex: 1, alignItems: 'flex-end', paddingRight: 10 }}>
<Switch
value={this.state.PIN}
onValueChange={() => this.togglePin()}
// disabled={true}
/>
</View>
</View>
<View style={{ height: 1, backgroundColor: VALER_CELLBORDER }} />
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ flex: 1, fontSize: 17 }}>Touch ID</Text>
<View style={{ flex: 1, alignItems: 'flex-end', paddingRight: 10 }}>
<Switch
value={this.state.touchID}
onValueChange={this.toggleTouchId.bind(this)}
/>
</View>
</View>
<View style={{ height: 1, backgroundColor: VALER_CELLBORDER }} />
</View>
<TouchableOpacity style={{ marginTop: 20 }} onPress={() => this.changePin()}>
<ButtonCell
section='2'
key='2'
Label="Change PIN"
Style={{ color: 'blue' }}
/>
</TouchableOpacity>
<View style={{ marginBottom: 30 }} />
</ScrollView>
)
}
}
const mapStateToProps = ({ state, action, auth }) => {
return {
state,
action,
user: auth.user
}
}
export default connect(mapStateToProps, null)(TouchIDPIN);
Use import TouchID from 'react-native-touch-id' on top of the js file.
enter image description here
Current Behaviour
The KeyBoardAvoidingView hides the Login button.
Its the same on Android and on iPhone.
On an Android Tablet It hides the Login button but since the screen is large you can see the button halfway from the top.
Expected Behaviour
I want the Login button at the bottom to move into the app frame when user wants to input his login details.
App.js
import React from 'react';
import { StyleSheet, Text, View,TouchableOpacity, AppRegistry} from 'react-native';
import { StackNavigator } from 'react-navigation'; // 1.0.0-beta.23
import Login from './screens/Login';
class App extends React.Component {
render() {
return (
<View
style={styles.container} >
<View style={styles.boxContainer}>
<View style = {[styles.boxContainer, styles.boxOne]}>
<Text style={styles.paragraph}>Tido</Text>
</View>
<View style={styles.boxContainerToggle}>
<TouchableOpacity style={[styles.boxContainer, styles.boxTwo]} onPress={() => this.props.navigation.navigate('Login')}>
<Text style={styles.paragraph}>Login</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.boxContainer, styles.boxThree]}>
<Text style={styles.paragraph}>Sign Up</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
boxContainer: {
flex: 1, // 1:3
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
boxContainerToggle: {
flex: 1,
flexDirection: 'row'
},
boxOne: {
flex: 6, // 5:6
justifyContent: 'space-around',
alignItems: 'center',
},
boxTwo: {
flex: 1, // 1:6
backgroundColor: 'powderblue',
flexDirection: 'row',
width: '50%',
height: '100%'
},
boxThree: {
flex: 1, // 1:6
flexDirection: 'row',
backgroundColor: 'skyblue',
width: '50%',
height: '100%'
},
paragraph: {
margin: 24,
fontSize: 27,
fontWeight: 'bold',
textAlign: 'center',
color: '#34495e',
},
});
const appScreens = StackNavigator({
Index: { screen: App },
Login: { screen: Login }
})
AppRegistry.registerComponent('tido', () => appScreens);
export default appScreens;
Login.js
import React from 'react';
import {StyleSheet, View, TextInput, TouchableOpacity, Text, KeyboardAvoidingView} from 'react-native';
export default class Login extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.boxContainer}>
<View style = {[styles.boxContainer, styles.boxOne]}>
<TextInput
style={styles.inputBox}
placeholder="username,email or phone"
placeholderTextColor="#00000030"
underlineColorAndroid="transparent">
</TextInput>
<TextInput
style={styles.inputBox}
secureTextEntry={true}
placeholder="password"
placeholderTextColor="#00000030"
underlineColorAndroid="transparent">
</TextInput>
</View>
<View style={styles.boxContainerToggle}>
<TouchableOpacity
style={[styles.boxContainer, styles.boxTwo]}>
<Text style={styles.paragraph}>Login</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
boxContainer: {
flex: 1, // 1:3
justifyContent: 'center',
},
boxContainerToggle: {
flex: 1,
flexDirection: 'row',
},
boxOne: {
flex: 5, // 5:6
backgroundColor: 'white',
padding: 20
},
boxTwo: {
flex: 1, // 1:6
backgroundColor: '#252525',
flexDirection: 'row',
width: '100%',
height: '100%',
alignItems: 'center'
},
inputBox: {
height: 40,
backgroundColor: '#B6B6B630',
marginBottom: 10,
paddingHorizontal: 10,
},
paragraph: {
fontSize: 27,
fontWeight: 'bold',
textAlign: 'center',
color: '#FFFFFF',
},
});
The problem is that KeyboardAvoidingView cannot correctly apply padding if it's children doesn't have plain size set. In this particular case you need to figure out the screen dimenson and apply screen height (minus navigation bar height) to your root View style:
import { Dimensions } from 'react-native';
const { screenHeight: height } = Dimensions.get('window');
const styles = StyleSheet.create({
...
containerContent: {
height: screenHeight - navBarHeight,
justifyContent: 'center',
}
...
},
And apply it in your render method:
render() {
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.containerContent}>
...
</View>
</KeyboardAvoidingView>
);
}
I am still seeing that on keyboard open the toolbar is being pushed up out of visible area. This is the code :
<KeyboardAvoidingView style={styles.containerContent}>
<View style={styles.containerContent}>
<GiftedChat
messages={}
onSend={this.onSend}
renderAvatar={null}
user={{
_id: 1,
}}
imageStyle={{}}
/>
</View>
</KeyboardAvoidingView>
const styles = StyleSheet.create({
containerContent: {
height: Dimensions.get('window').height - kHeaderHeight,
justifyContent: 'center',
flex: 1,
},
});
It seems that using WebView to open google maps(i.e. https://maps.google.com) will cause a fatal error. The function 'onNavigationStateChange' will be called infinite times. I print the navState parameter to log and the following is the output:
Log Output
Here is my code, which was modified from WebView Example.
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
TextInput,
TouchableWithoutFeedback,
TouchableOpacity,
View,
WebView
} = ReactNative;
var HEADER = '#3b5998';
var BGWASH = 'rgba(255,255,255,0.8)';
var DISABLED_WASH = 'rgba(255,255,255,0.25)';
var TEXT_INPUT_REF = 'urlInput';
var WEBVIEW_REF = 'webview';
var DEFAULT_URL = 'https://maps.google.com';
var WebViewExample = React.createClass({
getInitialState: function() {
return {
url: DEFAULT_URL,
status: 'No Page Loaded',
backButtonEnabled: false,
forwardButtonEnabled: false,
loading: true,
scalesPageToFit: true,
};
},
inputText: '',
handleTextInputChange: function(event) {
var url = event.nativeEvent.text;
if (!/^[a-zA-Z-_]+:/.test(url)) {
url = 'http://' + url;
}
this.inputText = url;
},
render: function() {
this.inputText = this.state.url;
return (
<View style={[styles.container]}>
<View style={[styles.addressBarRow]}>
<TouchableOpacity
onPress={this.goBack}
style={this.state.backButtonEnabled ? styles.navButton : styles.disabledButton}>
<Text>
{'<'}
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.goForward}
style={this.state.forwardButtonEnabled ? styles.navButton : styles.disabledButton}>
<Text>
{'>'}
</Text>
</TouchableOpacity>
<TextInput
ref={TEXT_INPUT_REF}
autoCapitalize="none"
defaultValue={this.state.url}
onSubmitEditing={this.onSubmitEditing}
onChange={this.handleTextInputChange}
clearButtonMode="while-editing"
style={styles.addressBarTextInput}
/>
<TouchableOpacity onPress={this.pressGoButton}>
<View style={styles.goButton}>
<Text>
Go!
</Text>
</View>
</TouchableOpacity>
</View>
<WebView
ref={WEBVIEW_REF}
automaticallyAdjustContentInsets={false}
style={styles.webView}
source={{uri: this.state.url}}
javaScriptEnabled={true}
domStorageEnabled={true}
decelerationRate="normal"
onNavigationStateChange={this.onNavigationStateChange}
onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
startInLoadingState={true}
scalesPageToFit={this.state.scalesPageToFit}
/>
<View style={styles.statusBar}>
<Text style={styles.statusBarText}>{this.state.status}</Text>
</View>
</View>
);
},
goBack: function() {
this.refs[WEBVIEW_REF].goBack();
},
goForward: function() {
this.refs[WEBVIEW_REF].goForward();
},
reload: function() {
this.refs[WEBVIEW_REF].reload();
},
onShouldStartLoadWithRequest: function(event) {
// Implement any custom loading logic here, don't forget to return!
return true;
},
onNavigationStateChange: function(navState) {
console.log(navState);
this.setState({
backButtonEnabled: navState.canGoBack,
forwardButtonEnabled: navState.canGoForward,
url: navState.url,
status: navState.title,
loading: navState.loading,
scalesPageToFit: true
});
},
onSubmitEditing: function(event) {
this.pressGoButton();
},
pressGoButton: function() {
var url = this.inputText.toLowerCase();
if (url === this.state.url) {
this.reload();
} else {
this.setState({
url: url,
});
}
// dismiss keyboard
this.refs[TEXT_INPUT_REF].blur();
},
});
var Button = React.createClass({
_handlePress: function() {
if (this.props.enabled !== false && this.props.onPress) {
this.props.onPress();
}
},
render: function() {
return (
<TouchableWithoutFeedback onPress={this._handlePress}>
<View style={[styles.button, this.props.enabled ? {} : styles.buttonDisabled]}>
<Text style={styles.buttonText}>{this.props.text}</Text>
</View>
</TouchableWithoutFeedback>
);
}
});
var ScaledWebView = React.createClass({
getInitialState: function() {
return {
scalingEnabled: true,
}
},
render: function() {
return (
<View>
<WebView
style={{
backgroundColor: BGWASH,
height: 200,
}}
source={{uri: 'https://facebook.github.io/react/'}}
scalesPageToFit={this.state.scalingEnabled}
/>
<View style={styles.buttons}>
{ this.state.scalingEnabled ?
<Button
text="Scaling:ON"
enabled={true}
onPress={() => this.setState({scalingEnabled: false})}
/> :
<Button
text="Scaling:OFF"
enabled={true}
onPress={() => this.setState({scalingEnabled: true})}
/> }
</View>
</View>
);
},
})
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: HEADER,
},
addressBarRow: {
flexDirection: 'row',
padding: 8,
},
webView: {
backgroundColor: BGWASH,
height: 350,
},
addressBarTextInput: {
backgroundColor: BGWASH,
borderColor: 'transparent',
borderRadius: 3,
borderWidth: 1,
height: 24,
paddingLeft: 10,
paddingTop: 3,
paddingBottom: 3,
flex: 1,
fontSize: 14,
},
navButton: {
width: 20,
padding: 3,
marginRight: 3,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: BGWASH,
borderColor: 'transparent',
borderRadius: 3,
},
disabledButton: {
width: 20,
padding: 3,
marginRight: 3,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: DISABLED_WASH,
borderColor: 'transparent',
borderRadius: 3,
},
goButton: {
height: 24,
padding: 3,
marginLeft: 8,
alignItems: 'center',
backgroundColor: BGWASH,
borderColor: 'transparent',
borderRadius: 3,
alignSelf: 'stretch',
},
statusBar: {
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 5,
height: 22,
},
statusBarText: {
color: 'white',
fontSize: 13,
},
spinner: {
width: 20,
marginRight: 6,
},
buttons: {
flexDirection: 'row',
height: 30,
backgroundColor: 'black',
alignItems: 'center',
justifyContent: 'space-between',
},
button: {
flex: 0.5,
width: 0,
margin: 5,
borderColor: 'gray',
borderWidth: 1,
backgroundColor: 'gray',
},
});
const HTML = `
<!DOCTYPE html>\n
<html>
<head>
<title>Hello Static World</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=320, user-scalable=no">
<style type="text/css">
body {
margin: 0;
padding: 0;
font: 62.5% arial, sans-serif;
background: #ccc;
}
h1 {
padding: 45px;
margin: 0;
text-align: center;
color: #33f;
}
</style>
</head>
<body>
<h1>Hello Static World</h1>
</body>
</html>
`;
exports.displayName = (undefined: ?string);
exports.title = '<WebView>';
exports.description = 'Base component to display web content';
exports.examples = [
{
title: 'Simple Browser',
render(): ReactElement<any> { return <WebViewExample />; }
},
{
title: 'Scale Page to Fit',
render(): ReactElement<any> { return <ScaledWebView/>; }
},
{
title: 'Bundled HTML',
render(): ReactElement<any> {
return (
<WebView
style={{
backgroundColor: BGWASH,
height: 100,
}}
source={require('./helloworld.html')}
scalesPageToFit={true}
/>
);
}
},
{
title: 'Static HTML',
render(): ReactElement<any> {
return (
<WebView
style={{
backgroundColor: BGWASH,
height: 100,
}}
source={{html: HTML}}
scalesPageToFit={true}
/>
);
}
},
{
title: 'POST Test',
render(): ReactElement<any> {
return (
<WebView
style={{
backgroundColor: BGWASH,
height: 100,
}}
source={{
uri: 'http://www.posttestserver.com/post.php',
method: 'POST',
body: 'foo=bar&bar=foo'
}}
scalesPageToFit={false}
/>
);
}
}
];
AppRegistry.registerComponent('test', () => WebViewExample);
If anyone can help me fix this problem, I would be really appreciated!
Don't know if you fix it, but here is an option if you want :
-Using <Mapview> and react-native-maps : look here