I am using RN 0.59. Every time I placed the app on the background then reopen it immediately, the SafeAreaView does not take the whole screen.
But, if I placed the app on the background and reopen it after a while (for about 3 seconds) it is working fine.
Here's my snippet on SafeAreaView
...
const SafeAreaViewUI = ({children}) => {
return (
<SafeAreaView style={styles.container}>
<View style={styles.content}>
{ children }
</View>
</SafeAreaView>
);
};
...
export default SafeAreaViewUI;
for my styling
container: {
flex: 1,
backgroundColor: Platform.OS === 'android' ? blurple : null,
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
},
content: {
flexGrow: 1,
color: text,
backgroundColor: white,
}
Any insight for this one?
This worked on my end.
const SafeAreaViewUI = ({children}) => {
const [ height, setHeight ] = useState(0)
return (
<SafeAreaView
onLayout={() => {
if (Platform.OS === 'android') {
setHeight(StatusBar.currentHeight || 0);
}
}}
style={[styles.container, { paddingTop: height }]}>
<View style={styles.content}>
{ children }
</View>
</SafeAreaView>
);
If there's other possible answer. Kindly post it here.
Thanks!
Related
I've been trying to understand how to use LayoutAnimation and the docs haven't been very helpful.
is there a better source? anyways here is this code which demonstrates the 3 different types of animations with layoutAnimation. It is an app with 3 buttons and 3 boxes which move across the screen differently. I am failing to understand what causes the boxes to animate. I don't see a function call making it animate. I only see conditional statements in the style attribute. the attribute seems to know nothing about the layoutAnimation. Yet it does animate.
here is the code
import React, { useState } from "react";
import {
View,
Platform,
UIManager,
LayoutAnimation,
StyleSheet,
Button
} from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
export default function App() {
const [firstBoxPosition, setFirstBoxPosition] = useState("right");
const [secondBoxPosition, setSecondBoxPosition] = useState("left");
const [thirdBoxPosition, setThirdBoxPosition] = useState("left");
const toggleFirstBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setFirstBoxPosition(firstBoxPosition === "left" ? "right" : "left");
};
const toggleSecondBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
setSecondBoxPosition(secondBoxPosition === "left" ? "right" : "left");
};
const toggleThirdBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setThirdBoxPosition(thirdBoxPosition === "left" ? "right" : "left");
};
return (
<View style={styles.container}>
{/* button demonstrating easing animation*/}
<View style={styles.buttonContainer}>
<Button title="EaseInEaseOut" onPress={toggleFirstBox} />
</View>
{/* button demonstrating linear animation*/}
<View style={styles.buttonContainer}>
<Button title="Linear" onPress={toggleSecondBox} />
</View>
{/* button demonstrating spring animation*/}
<View style={styles.buttonContainer}>
<Button title="Spring" onPress={toggleThirdBox} />
</View>
{/*The three boxes demonstrating animation types*/}
<View
style={[
styles.box,
firstBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View
style={[
styles.box,
secondBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View
style={[
styles.box,
thirdBoxPosition === "left" ? null : styles.moveRight
]}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
justifyContent: "center"
},
box: {
height: 100,
width: 100,
borderRadius: 5,
margin: 8,
backgroundColor: "blue"
},
moveRight: {
alignSelf: "flex-end"
},
buttonContainer: {
alignSelf: "center"
}
});
The idea (and the major gotcha) with LayoutAnimation is that it sets an animation for ALL subsequent layout changes until it's removed. It just works automatically with no additional setup.
I'm trying to display an image I have captured using expo-camera, from the camera component I'm trying to navigate to a new file which will display the image but after I took the image it won't navigate to the new page.
I tried importing the file and then navigate it but it still won't work and give me the warning instead.
This is the code where I tried to navigate to the new file.
export default class CameraExample extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
snap = async() => {
if(this.camera) {
console.log('Taking photo');
const options = {quality: 1, base64: true, fixOrientation: true, exif: true};
const photo = await this.camera.takePictureAsync(options);
this.props.navigation.navigate("Show", {photouri: photo.uri})
}
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type}
ref = {ref => {
this.camera = ref;
}}
>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity onPress={this.snap.bind(this)}>
<Ionicons
name = "md-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Ionicons
name = "md-reverse-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
And this is the code where I try to display the image.
export default class ShowImages extends React.Component{
render(){
console.log('OK')
const { navigation } = this.props;
const paramm = navigation.getParam('photouri');
return(
<Content>
<View>
<Text>
paramm: {JSON.stringify(paramm)}
</Text>
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.props.navigation.state.paramm.photouri}}
resizeMode="contain"/>
</View>
</Content>
)
}
}
I expect it to navigate to the new page and display the captured
image but it gave me the warning. I can't seem to find what is wrong with my code. Can anyone suggest what I should do? Thank you.
change this
<TouchableOpacity onPress={this.snap.bind(this)}> => <TouchableOpacity onPress={this.snap}>
Put it in the status value and pass it on.
export default class ShowImages extends React.Component{
constructor(props) {
super(props);
this.state = {
paramm: this.props.navigation.state.params.photouri
};
}
...
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.state.paramm }}
resizeMode="contain"/>
In React Native, how can I add a tab navigation in the middle of a screen?
So far, I have got a stack-navigator managing the overall navigation for my app. As I understand it, react-navigation has a default tab component, however that component appears to be placed at the bottom of the screen, not in the middle as desired here. I am also not clear on how to integrate it given that I already have the stack-navigator.
Current Approach:
Doing it manually as follows. Is there a better approach using react navigation to automatically handle click-effects and slide-in animations?
// set the tab-index on press
selectTab = ( index ) => {
this.setState({
activeIndex: index,
})
}
// render the content for the selected tab
renderTabContent = () => {
if( this.state.activeIndex == 1 ) {
return(
<View>
<Text>
This is the first section
</Text>
</View>
)
}
else if( this.state.activeIndex == 2 ) {
return(
<View>
<Text>
This is the second section
</Text>
</View>
)
}
else if( this.state.activeIndex == 3 ) {
return(
<View>
<Text>
This is the third section
</Text>
</View>
)
}
}
render() {
return (
<ScrollView>
<View style={{ flexDirection: 'row' justifyContent: 'space-around' }}>
<TouchableOpacity
onPress={() =>this.selectTab(1)}
style={[this.state.activeIndex == 1 ? { backgroundColor: 'red', width: 100 } : { backgroundColor: 'gray', width: 100, }]}
>
<Text>#1</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() =>this.selectTab(2)}
style={[this.state.activeIndex == 2 ? { backgroundColor: 'red', width: 100 } : { backgroundColor: 'gray', width: 100, }]}
>
<Text>#2</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() =>this.selectTab(3)}
style={[this.state.activeIndex == 3 ? { backgroundColor: 'red', width: 100 } : { backgroundColor: 'gray', width: 100, }]}
>
<Text>#3</Text>
</TouchableOpacity>
</View>
{this.renderTabContent()}
</ScrollView>
)
}
PS: Are there any beginner-friendly examples of real-world(ish) apps to get an idea of how common UI patterns are implemented in React Native?
You can use createBottomTabNavigator function of react-navigation library:
import { createBottomTabNavigator } from 'react-navigation';
And then create your stackNavigator :
export default createBottomTabNavigator({
Home: { screen: Home},
Search: { screen: Search},
History: { screen: History }
});
You can customize your tab appearance and behavior by following this link.
https://reactnavigation.org/docs/en/tab-based-navigation.html#customizing-the-appearance
For complete example you can refer:
https://github.com/react-navigation/react-navigation-tabs
I bought this Theme which in Expo works flawlessly, but as soon as I build the APK, the Keyboard will cover the whole screen and wont work as supposed.
I'm using expo for testing and it works just fine.
return (
<SafeAreaView style={styles.container}>
<NavHeader title={thread.name} {...{navigation}} />
<FlatList
inverted
data={messages}
keyExtractor={message => `${message.date}`}
renderItem={({ item }) => (
<Msg message={item} name={item.me ? name : thread.name} picture={thread.picture} />
)}
/>
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : "height"} enabled>
<View style={styles.footer}>
<TextInput
style={styles.input}
placeholder="Write a message"
value={this.state.message}
onChangeText={message => this.setState({ message })}
autoFocus
blurOnSubmit={false}
returnKeyType="send"
onSubmitEditing={this.send}
underlineColorAndroid="transparent"
/>
<TouchableOpacity primary transparent onPress={this.send}>
<Text style={styles.btnText}>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
And the Styles
const styles = StyleSheet.create({
container: {
flex: 1
},
footer: {
borderColor: Theme.palette.lightGray,
borderTopWidth: 1,
paddingLeft: Theme.spacing.small,
paddingRight: Theme.spacing.small,
flexDirection: "row",
alignItems: "center"
},
input: {
height: Theme.typography.regular.lineHeight + (Theme.spacing.base * 2),
flex: 1
},
btnText: {
color: Theme.palette.primary
}
});
I have tried the following plugin
using the enableOnAndroid prop
https://github.com/APSL/react-native-keyboard-aware-scroll-view
with no success.
I have posted here:
https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/305
and here:
https://github.com/expo/expo/issues/2172
Unfortunately this is a known issue
https://github.com/expo/expo/issues/2172
Depending on the complexity of your screen layout you could add a bottom margin or padding using Keyboard listeners provided by React Native.
import React, { Component } from 'react';
import { Keyboard, TextInput } from 'react-native';
class Example extends Component {
componentDidMount () {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow () {
this.setState({
marginBottom: 400
})
}
_keyboardDidHide () {
this.setState({
marginBottom: 0
})
}
render() {
return (
<TextInput
style={{marginBottom: this.state.marginBottom}}
onSubmitEditing={Keyboard.dismiss}
/>
);
}
}
I'm using react-native-navigation library on my project and i'm having some issues with my status bar. First one is that i'm unable to change my status bar background color on iOS, so i created a component for that as follow:
const S_StatusBar = ({ backgroundColor, ...props }) => (
<View style={[styles.statusBar, { backgroundColor }]}>
<StatusBar translucent backgroundColor={backgroundColor} {...props} />
</View>
);
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 :
StatusBar.currentHeight;
const styles = StyleSheet.create({
statusBar: {
height: STATUSBAR_HEIGHT,
}
});
I import this component on all my screen as followed:
<View>
<S_StatusBar backgroundColor="#090b4b" barStyle="light-content" />
</View>
Here is how i push my screen using the react-native-navigation library:
pushProductDetailScreen = () => {
this.props.navigator.push({
screen: 'cfl.ProductDetail'
});
};
The screen is pushed correctly but now my problem is that my status bar is under my navigation bar such as followed:
I don't understand the issue and why it's happening!
You are creating a View encapsulating something
<View style={[styles.statusBar, { backgroundColor }]}>
...
</View>
statusBar: {
height: STATUSBAR_HEIGHT,
}
So it does create a View with the specified height and backgroundColor
StatusBar is a component a bit different. It doesn't render anything but change the settings of your StatusBar.
You should be able to configure it from your View itself
<StatusBar
backgroundColor="blue"
barStyle="light-content"
/>
This styling works for me
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
class App extends Component {
render() {
return (
<View style={[styles.container]}>
<View style={[styles.statusbar]}>
<StatusBar barStyle="dark-content"/>
</View>
<WebView
style={[styles.webview]}
source={{ uri: "https://..." }}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
statusbar: {
height: STATUSBAR_HEIGHT,
},
webview: {
flex: 1,
}
});