Navigation using images nested inside Touchable Opacity - react-native

Background:
I've designed a custom footer for my app in React Native, I've set some images to act as icons. I'm trying to have them redirect to other pages of the app upon touch.
What I have tried
I've been trying to use the same images nested within TouchableOpacity components to have them redirect to other pages using react navigation.
This is my code:
export class Footer extends React.Component {
render (){
return (
<View style = { styles.footStyle } >
<TouchableOpacity onPress={ () => navigation.push('Home')} >
<Image
style = { styles.iconStyle }
source = {require('./img/home.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Favoritos')} >
<Image
style = { styles.iconStyle }
source = {require('./img/heart.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Search')} >
<Image
style = { styles.iconStyle }
source = {require('./img/search.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Notifications')} >
<Image
style = { styles.iconStyle }
source = {require('./img/bell.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Help')} >
<Image
style = { styles.iconStyle }
source = {require('./img/circle.png')}/>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
footStyle: {
paddingBottom: 0,
paddingRight: 10,
backgroundColor: '#ffffff',
flex: 0.4,
flexDirection: 'row',
borderTopWidth: 1,
borderTopColor: '#000000'
},
iconStyle: {
flex: 0.2,
height: undefined,
width: undefined
}
})
Problem
When I try and run the app in expo, the images are not rendering at all. I get my blank footer without any content. I've tried touching the footer to see if the images weren't rendering but the "button" actually worked, that didn't work.
Question
How exactly can I nest an image within a TouchableOpacity component? Is it even possible to use this method with React Navigation?
Thanks a lot!

For an Image component to work you should provide a height and width in style.
Here you are setting it as undefined
Try something like
iconStyle: {
flex: 0.2,
height: 100,
width: 100
}
Also on the navigation, you will have to pass the navigation prop to the Footer. As its a class you should access it as this.props.navigation.navigate()
As your code for integrating the Footer is not here, its hard to comment on how to pass the prop to the footer.

Related

How to display a button at the bottom of a Webview in react-native?

Inside my component (PrivacyPolicy.js), i have a header view, a webview, and a footer view. the webview, depending on the size, gets scrollable. my issue is that the footer view is displayed at the bottom of the screen like if its style was "position: 'absolute'" so it keeps displayed while scrolling. I need to have it after all webview is displayed.
<View style={styles.main_container}>
<View style={styles.header_container}>
...
</View>
<WebView originWhitelist={['*']} source={{ html: privacyPolicyContent }}/>
<View style={styles.footer_container}>
<CheckBox
disabled={false}
value={this.state.isChecked}
onValueChange={(newValue) => this.setState({
isChecked: newValue
})}
style={styles.checkbox}
tintColors={{ true: '#157dfa' }}
/>
<Text style={styles.checkbox_text}>I have read and accept the Privacy Polic</Text>
</View>
</View>
My styles:
const styles = StyleSheet.create({
main_container: {
flex: 1,
paddingHorizontal:'5%'
},
header_container: {
height: scale(90),
flexDirection: 'row',
marginLeft: 10
},
checkbox_container: {
flexDirection: 'row'
},
checkbox: {
marginLeft: -5,
},
checkbox_text: {
marginTop: 8,
fontSize: 10
}
})
I can see few suggestions:
Since your button is a React Native Button => You can show/hide based on the scrollY positions. For that, you need to communicate over the Bridge to dispatch an event accordingly.
As an alternative solution => You can create the button on the Webview its self to have the same functionality.

Component only reachable by scrolling regardless of window size

I'm trying to make a layout so that the later parts of the view are only reachable by scrolling.
Currently I'm using Dimensions to generate Views with the correct height. Is there a better way of doing so? My current solution doesn't seem too correct.
export default function MyApp() {
const height = Dimensions.get('window').height;
return (
<View style={styles.container}>
<ScrollView>
<View style={{backgroundColor: 'green', height:height}}/>
<View style={{backgroundColor: 'red', height:40}}/>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container:{
backgroundColor: 'white',
flex: 1
}
});
You can use VirtualizedList component, for example as
<VirtualizedList
data={['body']}
renderItem={({ item }) => (
<View style={styles.screen}>
{/* Put more content for body */}
</View>
)}
keyExtractor={(item, index) => index.toString()}
getItemCount={() => {
return 1;
}}
getItem={(data, index) => {
return data[index];
}}>
</VirtualizedList>
Your solution work, but not good and it have downside, when you change your phone orientation to landscape there will be bug. I dont like using Dimensions in my code unless there is no other way or use Dimensions addEventListener to listen window size and update component whenever window size change. I will suggest you a better way.
First, create a component called LayoutSizeAwareView, after this view rendered, we will catch it size from onLayout props and use them to render it children.
const LayoutSizeAwareView = (props) => {
const [size, setSize] = React.useState({width: 0, height: 0});
return (
<View
...props,
onLayout={(e) => {
setSize({
width: e.nativeEvent.layout.width,
height: e.nativeEvent.layout.height,
})
props.onLayout(e)
}}
>
{props.children(size)}
</View>
)
}
And then, in your case, use it like this
export default function MyApp() {
return (
<LayoutSizeAwareView style={styles.container}>
{({width, height}) => {
return (
<ScrollView>
<View style={{backgroundColor: 'green', height: height}}/>
<View style={{backgroundColor: 'red', height: 40}}/>
</ScrollView>
)
}}
</View>
);
}
const styles = StyleSheet.create({
container:{
backgroundColor: 'white',
flex: 1
}
});
This way your code look even cooler, there will be some typo in my code since I dont have IDE here, but you might get the idea.

Android: React Native Overlap TouchableOpacity and View behave differently when there is backgroundColor style

I created 2 Views that display overlaps to each others. The top and the bottom
When the bottom view background wasn't configured. It responded to the press event correctly. Let's say when I press on the overlap zone, it showed that the bottom one had been pressed
However, when I configured the bottom view backgroundColor. When I pressed on the overlap zone, on Android, it responded as I pressed on the top view which I think it's incorrect. (iOS it responded correctly that the bottom was pressed)
Steps To Reproduce
Provide a detailed list of steps that reproduce the issue.
Here is an example component
const OverlapseTouchExample = ({backgroundColor}) => {
const [pressedBox, setPressefBox] = React.useState('')
return (
<View>
<Text>{pressedBox} pressed</Text>
<TouchableOpacity style={[styles.box, {backgroundColor: 'blue'}]} onPress={() => setPressefBox('top')} />
<View style={backgroundColor ? { backgroundColor: 'orange' } : null}>
<View style={{marginTop: -75}}>
<TouchableOpacity style={[styles.boxBottom, backgroundColor ? { backgroundColor: 'green '} : null]} onPress={() => setPressefBox('bottom')} />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
box: {
width: 150,
height: 150,
borderWidth: 1,
},
boxBottom: {
width: 120,
height: 200,
borderWidth: 1,
}
})
The problem found when set the backgroundColor to true
<OverlapseTouchExample backgroundColor={true} />
You could see it in Snack https://snack.expo.io/#gie3d/9b6c32 (Android)

React Native Tab Bar white space under tabs

I am using a tab bar navigator with SafeAreaView.
If I comment out the tab bar nav the parent view covers the entire screen. However when I add a Tab bar it shows a small white view under the tab bar section.
const App = () => {
return (
<SafeAreaView style={styles.droidSafeArea}>
<View style={{ backgroundColor: "red", flex: 1 }}>
<TabNavigator key="MainTabNav" />
</View>
</SafeAreaView>
);
};
export default App;
const styles = StyleSheet.create({
droidSafeArea: {
flex: 1,
backgroundColor: "#2F3438",
}
});
Try this
screenOptions={{
tabBarStyle: {
paddingBottom:0,
},
}}
Please use the tab bar outside the safeAreaView else the safe area view will calculate the notch and will render the tab bar above the notch.
2.If you are using tab bar inside the safe area view use the force inset property of safe area view : <SafeAreaView forceInset = {bottom : 'never} this will make the safeareaview collide with bottom area and your tab bar will render properly.
Note : by using this method you would have to be a bit accurate in providing the styles.
const App = () => {
return (
<SafeAreaView style={styles.droidSafeArea} forceInset = {bottom : 'never'}>
<View style={{ backgroundColor: "red", flex: 1 }}>
<TabNavigator key="MainTabNav" />
</View>
</SafeAreaView>
);
};
export default App;
const styles = StyleSheet.create({
droidSafeArea: {
flex: 1,
backgroundColor: "#2F3438",
}
});
I had the exact same issue and what I did is not use SafeAreaView at all around the tab bar, but simply assigning the color I want the white space to have as the background color for the tab bar.
In your example that would be:
return (
<View>
<TabNavigator style={{ backgroundColor: "#2F3438" }} key="MainTabNav" />
</View>
);
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: Colors.tabIconSelected,
inactiveTintColor: Colors.tabIconDefault,
style: styles.container
}}/>
</NavigationContainer>
const styles = StyleSheet.create({
container: {
backgroundColor: Colors.darkBackgroundColor,
borderTopWidth: 0
}
});
Note : borderTopWidth: 0 worked for me
For react native navigation V5
<Tab.Navigator
tabBarOptions={{
style: {
borderTopWidth: 0
}
}}
>
<Tab.Screen/>
<Tab.Navigator>
Note: this is for bottom tab
When I was implementing floating button on bottomTabNavigation followed this post, I faced similar issue that tabBar has dirty white space with shadow(I used shadow in style of component).
I used React navigation v6.
issue image1, issue image2 (Sorry, It's my first Answer I post, I can't embed image yet)
I tried to remove it with borderWidth: 0, but not worked.
My case, below is worked for me.
Try this
borderRadius: 25 // some much number that near tabbar height
on
<Tab.Navigator
tabBar={(props) => (
<View style={styles.navigatorContainer}>
<BottomTabBar {...props} />
{isIphoneX() && (
<View
style={[
styles.xFillLine,
{ backgroundColor: "#fff" },
]}
/>
)}
</View>
)}
screenOptions={{
headerShown: false,
tabBarShowLabel: false,
tabBarStyle: {
borderRadius: 25, // add here
borderTopWidth: 0,
borderRadius: 25,
backgroundColor: "transparent",
elevation: 30,
},
tabBarItemStyle: { backgroundColor: "#fff" },
}}
>
...
Then result image is this.
I don't understand why It was worked, but I hope it works for someone.
I had this issue when i was using the TabBarIcon property within the Tab.Screen
Tab being const Tab = createBottomTabNavigator()
I couldn't solve the issue no matter how i used the SafeAreaView.
I solved it by not using the TabBarIcon property and instead making a custom component for the tabBar property on the higher level Tab.Navigator as outlined in the react native docs https://reactnavigation.org/docs/bottom-tab-navigator/
When i created the custom tabBar component it all worked as expected, no funky use of SafeAreaView.

Define right button of NavBar in component, not in Scene (react-native-router-flux)

I'm using react-native-router-flux for navigation in my app.
I want to define right button of NavBar in component, not in Scene, how should I do this?
Here is the code of the Scene:
<Scene
navBar={PlatformNavbar}
leftElement={ <Text style={{color: Colors.white, marginLeft: 25, fontWeight:'500' }}>Go Back</Text> }
key='nodScreen'
component={NodScreen}
hideNavBar={false}
/>
I'm using my custom navBar, I have functions for rendering right and left element: leftElement, rightElement.
In order to render right element in the component, I was using this code, however, it didn't render anything.
componentDidMount() {
Actions.refresh({rightElement: this.renderRightElement
}) }
renderRightElement = () => {
return ( <TouchableOpacity onPress={() => {} }>
<Image style={{height: 24, width: 24, marginRight: 16}} source={{uri: 'score_progress_empty'}} resizeMode='contain'/>
</TouchableOpacity>)
}
Have you tried using right instead of rightElement
componentDidMount() {
Actions.refresh({
right : this.renderRightElement,
})
}
Check out this issue on RNRF page for more details