I am using react navigation v5 to create my modal.
I want my modal to show in the beginning of 50% height, and when I press a button I want my modal to have 100% height. And toggle 50% to 100% to 50% back and forth.
However, I am unsure how to do this.
My code looks something like this.
Navigation
render(){
return (
<NavigationContainer>
<RootStack.Navigator mode="modal" headerMode = "none">
<RootStack.Screen name="home" component = {Home} />
<RootStack.Screen name="modala" component={ModalA}
options={{cardStyle: {backgroundColor: "transparent"}}}/>
</RootStack.Navigator>
</NavigationContainer>
);
}
As you can see I want my modalA to overlap Home component in the beginning as 50% width and if i press a button inside ModalA, I want my modal to be 100%. Is this possible?
Yes, its possible. To show the modal on the initial screen you must create this Modal Component on that screen
e.g
import React, { Component, useState } from 'react';
import {View, Text} from 'react-native';
import Modal from "react-native-modal";
const Home = (props) => {
const [height, setHeight] = useState('50%');
return (
<View>
<Modal isVisible={true}>
<View style={{ height, width: "80%", justifyContent: 'center', alignItems: 'center'}}>
<Text>I am the modal content!</Text>
<TouchableOpacity onPress={() => setHeight("50%")}>
<Text>Set 50% Height</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setHeight("100%")}>
<Text>Set 100% Height</Text>
</TouchableOpacity>
</View>
</Modal>
</View>
);
}
Related
I have a rather deeply nested component with a wrapper around the entire thing. I made sure its properly installed and imported from expo, so no errors and the component renders, just with no Linear Gradient above it. The code is as follows, NOTE that the colors are 'black' and 'white' for testing, but eventually 'white' will be changed with a transparent value
import React from 'react';
import { View, TouchableWithoutFeedback, Keyboard, ImageBackground, Image } from 'react-native';
import { LandingStyles } from '../../Styles/LandingPageStyles';
import LandingPageContainer from './LandingComponents/LandingPageContainer';
import Title from './LandingComponents/Title';
import backgroundImage from '../../assets/loginBackground.png'
import {LinearGradient} from 'expo-linear-gradient';
const LandingPage = ({ handleLoggedIn }) => {
return (
<LinearGradient colors={['black' ,'white']} start={{x: 0.5, y: 1 }} end={{x: 0.5, y: 0.7 }} style={{flex: 1}}>
<View style={LandingStyles.container}>
<ImageBackground style={LandingStyles.backdrop} source={backgroundImage} resizeMode="cover">
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={{backgroundColor: 'rgba(52, 52, 52, 0.4) !important',}}>
<View style={LandingStyles.titleIcon}>
<Title />
</View>
<LandingPageContainer handleLoggedIn={handleLoggedIn} />
</View>
</TouchableWithoutFeedback>
</ImageBackground>
</View>
</LinearGradient>
);
};
export default LandingPage;
Whenever I run the app to test, there's just no difference. I can comment out the Gradient and nothing changes. I've tried having it wrap the component (as shown above) or just being placed in as a single component (<LinearGradient /> instead of <LinearGradient> </LinearGradient>) but nothing works. Any ideas?
I have a text input in an overlay in my react native application. I used keyboardavoidingview to make sure the keyboard doesn't cover my submit button but the entire overlay is not moving with the keyboard only the inside content is moving. Heres an image of what is happening. Is there any way to move the overlay with the content too?
This is my code
<Overlay overlayStyle={{borderRadius:15,backgroundColor:'#f8f8f8',paddingTop:20,paddingLeft:20,height:300}} isVisible={showrevoverlay} onBackdropPress={()=>{resetoverlay()}}>
<KeyboardAvoidingView keyboardVerticalOffset={300} style={{flex:1,alignItems:'center',justifyContent:'center'}} behavior="padding">
<View style={{flexDirection:'column',justifyContent:'space-evenly',alignItems:'center'}}>
<Text style={{fontWeight:'bold',textAlign:'left',width:'100%'}}>Review:</Text>
<TextInput
placeholder="Write review"
style={{alignItems:'center',justifyContent:'center'}}
style={{ height: 200,width:300, borderColor: 'gray',backgroundColor:'#eef4f6',marginTop:10}}
onChangeText={text => setreview(text)}
value={review}
/>
<TO onPress={()=>{saveReview()}} style={{marginTop:10,width:100,height:50,backgroundColor:'#4B53F2',justifyContent:'center',alignItems:'center'}}><Text style={{fontFamily:'Montserrat-Bold',color:'white',fontSize:15}}>Submit</Text></TO>
</View>
</KeyboardAvoidingView>
</Overlay>
Here is the solution to solve this problem. you can add your code.
import React , {Component} from 'react';
import {View , Dimensions,ScrollView} from 'react-native';
const windowHeight = Dimensions.get('window').height;
export default class Overlay extends Component {
render(){
return(
<View style={{flex:1}}>
<ScrollView style={{flex:1}}>
<View style={{width:'100%', height:windowHeight }}>
/*Every thing inside this will shift up with out changing style */
</View>
</ScrollView>
</View>
)
}
}
I'm writing a customised modal for prompts on my react native application. I'd want the modal to appear on click of an image. So, I added an onPress to the image to change a state value. When the state value is true, I'd want the modal to be displayed. The state successfully becomes true. However, I'd want it to switch back to false after the modal closes.
I tried changing the values from inside the component but it throws an error since I'm importing the component, and passing values as props. Below is what I have:
const [showPrompt, setShowPrompt] = useState(false)
const show =() => {
setShowPrompt(true);
setShowPrompt(false)
console.log(showPrompt)
}
<TouchableOpacity onPress={show}>
<Image source={{uri: imageSource}} style={{height:130, width:150}}/>
<Text style={{color:'white', textAlign:'center', fontSize:16, fontFamily:fonts.nunitoRegular}}>{title}</Text>
</TouchableOpacity>
{showPrompt && <CustomPrompt
open={modalVisible}
onClose={()=> setModalVisible(!modalVisible)}
openModalText={()=>setModalVisible(true)}
/>
}
try useCallback()
setShowPrompt(true);
//the time between these 2 operations is just a Boolean value assignment,
//that is, it is only a few milliseconds and you would be able to view
//the rendering
setShowPrompt(false);
import React, {useState, useCallback} from 'react'
const show = useCallback(() => {
setShowPrompt(!showPrompt);
console.log(showPrompt)
}, [showPrompt]);
<TouchableOpacity onPress={show}>
<Image source={{uri: imageSource}} style={{height:130, width:150}}/>
<Text
style={{
color:'white',
textAlign:'center',
fontSize:16,
fontFamily:fonts.nunitoRegular}}>
{title}
</Text>
</TouchableOpacity>
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 was trying to position a button on the bottom right of the screen like the picture below:
So, basically I had a Scrollview with the button inside like so:
import React, { Component } from 'react'
import { ScrollView, Text, KeyboardAvoidingView,View,TouchableOpacity } from 'react-native'
import { connect } from 'react-redux'
import { Header } from 'react-navigation';
import CreditCardList from '../Components/credit-cards/CreditCardList';
import Icon from 'react-native-vector-icons/Ionicons';
import Button from '../Components/common/Button';
// Styles
import styles from './Styles/CreditCardScreenStyle'
import CreditCardScreenStyle from './Styles/CreditCardScreenStyle';
class CreditCardScreen extends Component {
render () {
return (
<ScrollView style={styles.container}>
<CreditCardList />
<TouchableOpacity style={CreditCardScreenStyle.buttonStyle}>
<Icon name="md-add" size={30} color="#01a699" />
</TouchableOpacity>
</ScrollView>
)
}
}
My styles:
import { StyleSheet } from 'react-native'
import { ApplicationStyles } from '../../Themes/'
export default StyleSheet.create({
...ApplicationStyles.screen,
container:{
marginTop: 50,
flex: 1,
flexDirection: 'column'
},
buttonStyle:{
width: 60,
height: 60,
borderRadius: 30,
alignSelf: 'flex-end',
// backgroundColor: '#ee6e73',
position: 'absolute',
bottom: 0,
// right: 10,
}
})
The problem is that the absolute positioning does not work at all when the button is inside the ScrollView. But...If I change the code to look like this:
import CreditCardScreenStyle from './Styles/CreditCardScreenStyle';
class CreditCardScreen extends Component {
render () {
return (
<View style={styles.container}>
<ScrollView >
<CreditCardList />
</ScrollView>
<TouchableOpacity style={CreditCardScreenStyle.buttonStyle}>
<Icon name="md-add" size={30} color="#01a699" />
</TouchableOpacity>
</View>
)
}
}
Then it works !! Whaat? Why? How? I don't understand why this is happening and I would appreciate any information about it.
This might be inconvenient but is just how RN works.
Basically anything that's inside the ScrollView (in the DOM/tree) will scroll with it. Why? Because <ScrollView> is actually a wrapper over a <View> that implements touch gestures.
When you're using position: absolute on an element inside the ScrollView, it gets absolute positioning relative to its first relative parent (just like on the web). Since we're talking RN, its first relative parent is always its first parent (default positioning is relative in RN). First parent, which in this case is the View that's wrapped inside the ScrollView.
So, the only way of having it "fixed" is taking it outside (in the tree) of the ScrollView, as this is what's actually done in real projects and what I've always done.
Cheers.
i suggest to use "react-native-modal".
you can not use position: 'absolute' to make elements full size in ScrollView
but you can do it by
putting that element in modal wrapper.
below are two examples. first one doesnt work but the second one works perfectly.
first way (doesnt work):
const app = () => {
const [position, setPosition] = useState('relative')
return(
<ScrollView>
<Element style={{position: position}}/>
<Button
title="make element fixed"
onPress={()=> setPosition('absolute')}
/>
</ScrollView>
)
}
second way (works perfectly):
const app = () => {
const [isModalVisible, setIsModalVisible] = useState(false)
return(
<ScrollView>
<Modal isModalVisible={isModalVisible}>
<Element style={{width: '100%', height: '100%'}}/>
</Modal>
<Button
title="make element fixed"
onPress={()=> setIsModalVisible(true)}
/>
</ScrollView>
)
}
for me this worked:
before:
<View>
<VideoSort FromHome={true} />
<StatisticShow style={{position:'absulote'}}/>
</View>
after:
<View>
<ScrollView>
<VideoSort FromHome={false} />
</ScrollView>
<View style={{position:'relative'}}>
<StatisticShow style={{position:'absulote'}}/>
</View>
</View>