I have a screen with a structure like this
<View>
...Header Element
<Tab.Navigator
screenOptions={{
tabBarLabelStyle: { textTransform: 'none' },
}}
>
<Tab.Screen name="New" component={NewData} />
<Tab.Screen name="Old" component={OldData} />
</Tab.Navigator>
</View>
export default function OldData() {
return (
<View>
<Button
mode="contained"
style={styles.btn}
labelStyle={{ color: Colors.white }}
onPress={() => setShowModal(!showModal)}
uppercase={false}
>
Open Modal
</Button>
</View>
)
}
What I want to accomplish is to trigger a button on one of the Tab Screen (ex. OldData) and then open a modal on the entire View covering both Header Element and Tab Navigator, as right now the button on the OldData component only shows a modal on top of the OldData component only
Is that doable? Or can I only do a function call inside Tab Screen?
Related
I am trying to close a React Navigation modal from the navigation stack.
Following the official React Navigation documentation navigation.goBack''' is being used within the '''Modal Screen. This successfully closes the modal, but what I would like to achieve is closing the modal by pressing a button in the navigation stack instead of in the screen.
I have tried both of the below functions and although they work as expected in the Screen, they do not work in the stack navigator.
<Button onPress={() => navigation.pop()} title="Dismiss" />
<Button onPress={() => navigation.goBack()} title="Dismiss" />
I get the following error:
undefined is not an object (evaluating 'navigation.goBack')
How can I get the modal to close by pressing a button in the stack navigator?
I think you have misunderstood this Example.
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is the home screen!</Text>
<Button
onPress={() => navigation.navigate('MyModal')}
title="Open Modal"
/>
</View>
);
}
function ModalScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is a modal!</Text>
<Button onPress={() => navigation.goBack()} title="Dismiss" />
</View>
);
}
const RootStack = createStackNavigator();
function RootStackScreen() {
return (
<RootStack.Navigator>
<RootStack.Group>
<RootStack.Screen name="Home" component={HomeScreen} />
</RootStack.Group>
<RootStack.Group screenOptions={{ presentation: 'modal' }}>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Group>
</RootStack.Navigator>
);
}
Note:
both HomeScreen and ModalScreen are screen not model of any kind. screenOptions is an object where you define what type of animation you want to see when user navigate to that screen.
when you set screenOptions to model:
The modal behavior slides the screen in from the bottom and allows the
user to swipe down from the top to dismiss it on iOS.
Finally let talk about your error:
undefined is not an object (evaluating 'navigation.goBack')
navigation props will only be available on those screen which are include in your navigation.
so check that screen is present or not where your accessing navigation.goBack
Lets say I am in the tab - ChatStack and I am on the screen stack - AllChatRooms. Then when I click on one of the chat rows, I am then navigated to the chat room. I have it coded that, when in the ChatRoom screen, don't display nav bar and that works. But the ChatRoom screen does not reach full height and it acts like the nav bar is still there. I attached an image with colors so you can see what I am talking about.
Would really appreciate some help if anyone knows how to get the screen to reach the bottom of the phone screen.
So I am using a bottom tab navigator like this (simplified version):
Tabs.js
const getRouteName = (route) => {
const routeName = getFocusedRouteNameFromRoute(route);
if (routeName?.includes("HomeAllCategories") || routeName === "ChatRoom") {
return "none";
}
return "flex";
}
return (
<Tab.Navigator screenOptions={{ tabBarShowLabel: false }}>
<Tab.Screen name="Home" component={HomeStack}/>
<Tab.Screen name="Bookmarks" component={BookmarkStack}/>
<Tab.Screen name="Chats" component={ChatStack} options={({route}) => ({
tabBarStyle: {display: getRouteName(route)},
})}/>
<Tab.Screen name="Settings" component={SettingsStack}/>
</Tab.Navigator>
)
ChatStack.js
<Stack.Navigator>
<Stack.Screen name="AllChatRooms" component={AllChatRooms} />
<Stack.Screen name="ChatRoom" component={ChatRoom} />
</Stack.Navigator>
ChatRoom.js
return (
<SafeAreaView className="flex-1 bg-slate-900">
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="flex-1"
keyboardVerticalOffset={10}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<FlatList
data={messages}
className="pl-4"
keyExtractor={item => item.id}
renderItem={({ item }) =>
item.from === user.name ? (
<ReceiverMessage message={item} />
) : (
<SenderMessage message={item} />
)
}
/>
</TouchableWithoutFeedback>
{/* Text Box */}
<View className="bg-white flex-row justify-between items-center border border-gray-200 px-5 py-2">
<TextInput
className="h-10 text-lg w-4/5"
placeholder="Send Message..."
/>
<Button title="Send" color="#6ECCAF"/>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
)
and I'm using:
"#react-navigation/bottom-tabs": "^6.5.2",
"#react-navigation/native": "^6.1.1",
"#react-navigation/native-stack": "^6.9.7",
But sometimes it does have the full height and I don't know why? On launch, the height of the screen is never working but after leaving and opening the chat room several times, the height of the screen does reach the bottom. Why is that?
I am using flatlist in my app to show the result of the game by using API, I have a button outside the flatlist, I want the user to click the button and by clicking the button toggle switch will appear with each game and a user can switch off to hide the games and switch on to show the games.
First problem how can I link the button with the render function of flatlist to show the toggle switch.
Seconde is that how can I use the toggle switch to show and hide the games in flatlist.
<View style={{flex:1,}}>
<TouchableOpacity onPress={this.renderItem }> // What should I do here?
<Text style={{fontSize:30,color:'blue'}}>show/hide</Text>
</TouchableOpacity>
<DraggableFlatList
data={this.state.dataSource}
onDragEnd={this.dataSource}
renderItem={this.renderItem}
keyExtractor={item => item.GameId.toString()}
ItemSeparatorComponent={this.renderSeprator}
refreshing = {this.state.refreshing}
onRefresh = {this.handleRefresh}
/>
renderItem=({item,navigation,drag,btnvalue1})=>{
const current = new Date();
const currentHour = current.getHours();
return(
<ScaleDecorator>
<TouchableOpacity style={styles.item}
onLongPress={drag}
onPress={
() => this.props.navigation.navigate('ResultsStack',
{ screen: 'Result', params: { resultDate: this.state.resultDate ,GameId: item.GameId } }
//() => this.props.navigation.navigate('ResultsStack', { screen: 'Result' }
)} >
<Image style={styles.img}
source={{
uri: item.ImgUrl,
}}
/>
<Text style={styles.title}>{item.GameDescp} [{item.DrawRef}] [{item.DayName?.slice(0, 3)}]</Text>
<Text style={styles.txt3}>{item.Result03}</Text>
**//On click I want to hide this Ionicon and show a toggle switch**
<Ionicons
name="chevron-forward-outline"
style={styles.iconarrow}
//color={color}
size={30}
></Ionicons>
{this.btnvalue1 === 1 ? (
<Switch
style={styles.iconarrow}
trackColor={{ false: "#767577", true: "#81b0ff" }}
ios_backgroundColor="#3e3e3e"
/>) : null}
</TouchableOpacity>
</ScaleDecorator>
Looking at this example from React Navigation website, between Chat and Contacts, the heights are independent of each other. However, When I tried to implement a top bar, the heights are the same. It takes the height of which ever tab has the most content in it.
But in the example, you can see in Contacts that there may be more contacts where you can scroll, and in Chat, the input field is at the bottom, making it look like that's where it stops.
Here's a screen shot from the example:
Chat tab
Contacts tab
Here's some of my code and what I'm experiencing:
<View style={{backgroundColor: 'orange'}}>
{!loading &&
!loadingProfileInfo &&
typeof data.infoByUser !== 'undefined' && (
<FlatList
data={data.infoByUser}
ListHeaderComponent={
<View>
<UserInfo />
<Tab.Navigator>
<Tab.Screen
name="Test"
component={TestComponent} />
<Tab.Screen
name="New Tab"
component={NewTabComponent}
/>
</Tab.Navigator>
</View>
}
numColumns={2}
renderItem={({item}) => (
<View>
// ...
</View>
)}
keyExtractor={item => item._id}
/>
)}
</View>
TestComponent
<View style={{backgroundColor: 'grey'}}>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
</View>
NewTabComponent
<View style={{backgroundColor: 'red'}}>
<Text>new tab</Text>
</View>
Notice how the New Tab has a big gap between the red and the orange, that's from the Test tab's height.
You are rendering your entire navigator as the FlatList 'header'. You shouldn't even use Flatlist in this component. Each screen has a different number of items, and should have its own Flatlist.
To fix this:
Remove the FlatList from your main component (with backgroundColor: 'orange'), and just render the Tab Navigator in that render function.
Inside of TestComponent and NewTabComponent, render a ScrollView (or FlatList) if you need it.
All screens (TestComponent and NewTabComponent) should have a height: '100%' or flex: 1 if you want all screens to take all up all the space of the screen, even when its real height is less than the screen height.
To have heights according to the content inside the particular tab, use Scrollview inside each tab screen. Thank me later if this works perfectly. :)
import * as React from "react";
import { ScrollView, Text, View } from "react-native";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
function Screen1() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen1 </Text>
</View>
</ScrollView>
);
}
function Screen2() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen2</Text>
</View>
</ScrollView>
);
}
function Screen3() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen3 </Text>
</View>
</ScrollView>
);
}
const Tab = createMaterialTopTabNavigator();
export default function TopBarNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="Screen1" component={Screen1} />
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
</Tab.Navigator>
);
}
I'm having no idea why you're rendering it inside FlatList as it also inherits props from Scroll View.
<View style={{backgroundColor: 'orange'}}>
<Tab.Navigator>
<Tab.Screen
name="Test"
component={TestComponent} />
<Tab.Screen
name="New Tab"
component={NewTabComponent}
/>
</Tab.Navigator>
</View>
and move the FlatList and other business logics inside the TestComponent or the NewTabComponent.
The point is don't render Tabs inside ScrollView or FlatList or SectionList as they both inherit the props of ScrollView.
After a long research I found out that your problem is because react-native-tab-view (which is used by material-tob-tabs), has this code :
_defineProperty(this, "handleLayout", e => {
const {
height,
width
} = e.nativeEvent.layout;
if (this.state.layout.width === width && this.state.layout.height === height) {
return;
}
this.setState({
layout: {
height,
width
}
});
With option lazy={true} , and using the "New Tab" component on first tab and "Test" on second, you get the right height until you change the tab. When you press on "Test" the layout changes so the height is bigger. After changing tab the height does't change anymore because the layout stays the same ("New Tab" fits perfectly in the bigger height) and doesn't trigger handleLayout from react-native-tab-view.
Hope you can find a way to change the layout again when you change tabs.
I have modal for filtering search resluts , something like foursquare app . I have filters in diffrent categories and I need to use tabs for each category . for example when user clicks each tabs it shows the filters related to that tab . and user can select checkboxes or radio buttons . and at the end when user checks all of their needed filters I need to make http request with the new filters.
Something like the image below . I created the modal but I need the functionality for tabs and at the end making the api request with the selected options:
You can also create custom tabs using <Text> with state and depending on a state value render a View associated with that tab. for example
state = {
modalVisible: false,
currentTab: 1,
};
onTabClick = (currentTab) => {
this.setState({
currentTab: currentTab,
});
};
// inside render
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.tabs}>
<Text
onPress={() => {
this.onTabClick(1);
}}
style={[
styles.tabTextStyle,
this.state.currentTab === 1 ? styles.tabUnderline : null,
]}>
GENDER
</Text>
...
</View>
{this.state.currentTab === 1 && (
<View>
<Text>GENDER</Text>
</View>
)}
...
snack example
Modal is just a Container like View. You can draw anything inside it.
First, import {Modal} from 'react-native'
Then, in your modal, embed anything what you want:
<Modal visible={ this.state.modal }
animationType="fade" transparent={true}
onRequestClose={_ => this.setState({ modal: false }) }>
<View>
{/*
Do anything. Its an open ground.
Whatever component, styles, props and/or anything else you want, you can design
*/}
{/* For example, I am adding a close button */}
<TouchableOpacity style={{ alignSelf: 'flex-end' }} onPress={_ => this.setState({ modal: false }) }>
<Icon type="FontAwesome" name='times' style={ styles.closeIcon } />
</TouchableOpacity>
</View>
</Modal>
And you can open your modal from anywhere like:
<TouchableOpacity style={ styles.button } onPress={_ => this.setState({ modal: true }) }>
<Text style={ styles.buttonText }>Open Modal</Text>
</TouchableOpacity>
Finally, for tabs, you can use either of:
NativeBase Tab Component
React Native Tab View