Lets say i have <ListingCard/> components inside of a
<ScrollView/> .
What i want is render those <ListingCard/> side by side on a container class.
Here is What i have tried so far:
<ListingCard/>
const ListingCard = (props) => {
return (
<View style={styles.container}>
<Text>This is ListingCard Component</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
//flex: 1,
alignItems: 'center',
justifyContent: 'center',
height: 150,
width: Dimensions.get('window').width / 2 - 6,
backgroundColor: colors.WHITE,
borderRadius: 5,
marginHorizontal:10,
marginBottom: 10
},
});
export default ListingCard;
here is how i used <ListingCard/> :
render() {
const { currentCategory } = this.state;
return (
<Drawer
ref={(ref) => this._drawer = ref}
type="static"
onOpenStart={() => {
this.setState({
isDrawerOpen: true,
})
}}
onClose={() => {
this.setState({
isDrawerOpen: false,
})
}}
content={<SideFilterMenu />}
tapToClose={true}
side={'right'}
openDrawerOffset={0.2} // 20% gap on the right side of drawer
panCloseMask={0.2}
closedDrawerOffset={-3}
>
<View style={styles.container}>
<CustomHeader
onPress={() => this.handleFilterPress()}
headerText={currentCategory && currentCategory.categoryName}
isIconVisible={true}
rightButtonText={'Filtrele'}
onIconPress={() => this.handleBackPress()}
/>
<ScrollView
style={{flex:1}}
contentContainerStyle={styles.cardContainer}
>
<ListingCard />
<ListingCard />
<ListingCard />
<ListingCard />
<ListingCard />
<ListingCard />
<ListingCard />
<ListingCard />
</ScrollView>
</View>
</Drawer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
//alignItems: 'center',
//justifyContent: 'center',
backgroundColor: colors.GENERAL_BCK,
//paddingHorizontal: 5
},
cardContainer: {
flexDirection: 'row',
flexWrap: 'wrap'
}
});
What i have tried is, with or without <View> container but this isnt helped at all. The reason i could not accoplish it is i am relatively new on ReactNative and have struggle with those stylings.
I could not accomplish to render those <ListingCard/> side by side. Any help will be appreciated, thanks.
Ok, i have fixed it.
Problem was <ListingCard/>'s width.
it was: width: Dimensions.get('window').width / 2 - 6, which was too wide to fit two of them on same row. so i changed it to: width: Dimensions.get('window').width / 2 - 20, and voila! it's worked.
Related
I have this <ScrollView />
<ScrollView
style={styles.scrollview}>
{route.params && route.params....map((cat, index) => {
return <Kitten
cat={cat}
key={index} />
})}
</ScrollView >
const styles = StyleSheet.create({
scrollview: {
paddingLeft: 15,
paddingRight: 15,
backgroundColor: 'white',
flex: 1,
},
});
into which I want to put this <BackgroundImage />.
import { ImageBackground } from 'react-native';
const image = require('...')
const Kittens = ({ children }) => {
return <ImageBackground
source={image}
resizeMode='repeat'
style={{ width: '100%', height: '100%' }}>
{children}
</ImageBackground>
}
I want the background image to be fixed, so that the content scrolls over the image. I further shall fill the whole screen. How would I do that?
use the scrollview as the child of ImageBackground
<ImageBackground
source={{uri://image url here}}
style={{
}}
>
<ScrollView
style={styles.scrollview}
contentContainerStyle={}
>
{route.params && route.params....map((cat, index) => {
return <Kitten cat={cat} key={index} />
})}
</ScrollView >
</ImageBackground>
If the parent of the Kittens fills the screen, removing white backgroundColor should work. You can play with resizeMode to get the best result from your image.
<Kittens>
<ScrollView
style={styles.scrollview}>
{route.params && route.params....map((cat, index) => {
return <Kitten cat={cat} key={index} />
})}
</ScrollView >
</Kittens>
const styles = StyleSheet.create({
scrollview: {
paddingLeft: 15,
paddingRight: 15,
//backgroundColor: 'white',
flex: 1,
},
});
<ImageBackground
source={{uri:image url}}
style={{height:"100%", width:"100%"}}
>
<ScrollView
contentContainerStyle={flexGrow:1}
>
<View style={{flex:1}} >
</View>
</ScrollView >
</ImageBackground>
I want to achieve something like this in React Native:
I have a TextInput component and I want to put an icon to the right side. The user can click it, then I can display some text in a modal or in a another component.
Is this possible in react native?
return(
<View style={styles.container}>
<TextInput
placeholder="Állat neve"
value={AllatNev}
style={styles.textBox}
onChangeText={(text) => setAllatNev(text)}
/>
</View>
);
}
)
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: color_theme_light.bodyBackground
justifyContent: 'center',
alignItems:'center'
},
textBox:{
borderWidth:2,
borderColor: color_theme_light.textBoxBorder,
margin:15,
borderRadius:10,
padding: 10,
fontFamily:'Quicksand-Medium'
},
});
Yes -- you can position your info button over the TextInput using absolute positioning and a zIndex, for example:
import * as React from 'react';
import { Text, View, StyleSheet, TextInput, TouchableOpacity } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.textBoxParent}>
<TextInput style={styles.textBox} placeholder="Állat neve"/>
<TouchableOpacity style={styles.textBoxButton} onPress={() => {
//launch your modal
}}>
<Text>i</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
textBoxParent: {
justifyContent: 'center'
},
textBox:{
borderWidth:2,
borderColor: 'gray',
margin:15,
borderRadius:10,
padding: 10,
},
textBoxButton: {
position: 'absolute',
right: 20,
zIndex: 100,
width: 20,
height: 20,
borderWidth: 1,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center'
}
});
Working example: https://snack.expo.dev/OFMTc8GHE
Heres a full example of what you want (https://snack.expo.dev/bjzBFuE4W). And below I explain the code.
Fist I made a Modal from react native that takes in modalVisible, setModalVisible, and appears when modalVisible is true.
import * as React from 'react';
import { Text, View, StyleSheet,TextInput ,TouchableOpacity,Modal} from 'react-native';
import { AntDesign } from '#expo/vector-icons';
import { MaterialIcons } from '#expo/vector-icons';
const ModalInfo = ({modalVisible, setModalVisible})=>{
return (
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<View style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}>
<View
style={{
width:200,height:200,backgroundColor:"gray",borderWidth:2,
justifyContent:"center",alignItems:"center"
}}
>
<TouchableOpacity onPress={()=>{setModalVisible(false)}}>
<MaterialIcons name="cancel" size={24} color="black" />
</TouchableOpacity>
</View>
</View>
</Modal>
)
}
Next I made a View to wrap around the textInput so I can also add an svg of the info icon. And then set the outside view to have flexDirection:"row", so everything would be ordered the way you wan't.
const TextInputWithModal = ()=>{
const [modalVisible, setModalVisible] = React.useState(false);
const [AllatNev,setAllatNev]= React.useState("");
return (
<View style={styles.textInputContainer}>
<TextInput
placeholder="Állat neve"
value={AllatNev}
style={styles.textBox}
onChangeText={(text) => setAllatNev(text)}
/>
<TouchableOpacity onPress={()=>{setModalVisible(true)}}>
<AntDesign name="infocirlceo" size={24} color="black" />
</TouchableOpacity>
<ModalInfo modalVisible={modalVisible} setModalVisible={setModalVisible}/>
</View>
)
}
export default function App() {
return (
<View style={styles.container}>
<TextInputWithModal/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems:"center",
},
textInputContainer:{
borderRadius:10,
padding: 10,
flexDirection:"row",
margin:15,
borderWidth:2,
},
textBox:{
fontFamily:'Quicksand-Medium',
marginRight:20,
},
});
On my screen, I type in the input field and get search results accordingly. The list is rendered within a ScrollView but it still doesn't let me scroll when the keypad is open (in Android at least).
How can I fix this?
This is the component where the scroll view is rendered.
export const LocationsFound: React.FunctionComponent<LocationsFoundProps> = ({
addressesFound,
}) => {
return (
<>
{addressesFound.length > 0 ? (
<KeyboardAwareScrollView
style={styles.searchResultsContainer}
keyboardShouldPersistTaps={'always'}
keyboardDismissMode={'on-drag'}
>
{addressesFound.map((addressDetails: addressDetailsType) => {
return (
<View
key={addressDetails.placeName}
style={styles.resultContainer}>
<Text
style={styles.text}
onPress={() => handleLocationSelection(addressDetails)}>
{addressDetails.placeName}
</Text>
</View>
);
})}
</KeyboardAwareScrollView>
) : null}
</>
);
};
const styles = StyleSheet.create({
searchResultsContainer: {
width: moderateScale(400),
paddingHorizontal: moderateScale(50),
paddingRight: moderateScale(65),
marginTop: moderateScale(10),
},
resultContainer: {
marginTop: moderateScale(10),
borderBottomWidth: 1,
borderBottomColor: 'grey',
},
text: {
fontSize: moderateScale(15),
},
});
This is the component where the LocationsFound component is called.
return (
<SafeAreaView style={styles.safeAreaViewContainer}>
<View style={styles.container}>
<View style={styles.searchFieldContainer}>
<AddressSearchInput
addressType="favouritePoint"
placeholder="Ort eingeben"
/>
</View>
<View style={styles.dropdown}>
<LocationsFound
addressesFound={locations.addressesFoundList}
/>
</View>
</View>
</SafeAreaView>
);
};
export const styles = StyleSheet.create({
safeAreaViewContainer: {
flex: 1,
},
container: {
height: '100%',
backgroundColor: 'white',
width: '100%',
display:"flex",
flexDirection:"column",
flex: 1
},
dropdown: {
position: 'absolute',
top: moderateScale(215),
zIndex: moderateScale(10),
backgroundColor: '#fff',
flex: 1
},
});
I also tried adding
onScrollBeginDrag={Keyboard.dismiss}
but it doesn't make a difference.
sounds like a height, issue, without all the code, no one is going to give your clear answers without speculation. the keyboard doesn't shrink the view, check out this package, it may help - https://github.com/APSL/react-native-keyboard-aware-scroll-view
I added a button in tabBarIcon and it is not completely hidden when using tabBarVisible,my code:
file: App.js
i'm just added a different icon in AddScreen.
import HomeStack from './stacks/Home';
import UserStack from './stacks/User';
import AddStack from './stacks/Add';
import AddIcon from './AddIcon';
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeStack}
options={{
tabBarIcon: () => <IconAnt name={'home'} style={styles.icon} />,
}}
/>
<Tab.Screen
name="Add"
component={AddStack}
options={{
tabBarIcon: () => <AddIcon />, // icon add
title: '',
}}
/>
<Tab.Screen
name="User"
component={UserStack}
options={{
tabBarIcon: () => <IconAnt name={'user'} style={styles.icon} />,
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
file: stacks/Home.js
when press 'go to detail', I'm hide the tabbar
function HomeScreen({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Home!</Text>
<TouchableOpacity onPress={() => navigation.navigate('Detail')}>
<Text>go to detail/Text>
</TouchableOpacity>
</View>
);
}
function DetailScreen() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Detail!</Text>
</View>
);
}
const HomeStack = createStackNavigator();
export default function ({navigation, route}) {
var tabBarVisible = true;
if (typeof route.state !== 'undefined') {
const {routes} = route.state;
if (routes.length > 1) {
tabBarVisible = false;
}
}
navigation.setOptions({tabBarVisible});
// tabbar will hide when moving to Detail screen
return (
<HomeStack.Navigator>
<HomeStack.Screen name={'Home'} component={HomeScreen} />
<HomeStack.Screen name={'Detail'} component={DetailScreen} />
</HomeStack.Navigator>
);
}
AddIcon.js
file icon of AddScreen
export default function () {
return (
<View style={styles.container}>
<View style={styles.button}>
<IconAnt name={'plus'} style={{fontSize: 30, color: '#fff'}} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
alignItems: 'center',
zIndex: 99,
},
button: {
alignItems: 'center',
justifyContent: 'center',
width: 72,
height: 72,
borderRadius: 72 / 2,
backgroundColor: 'red',
position: 'absolute',
marginTop: -45,
shadowColor: 'red',
shadowRadius: 5,
shadowOffset: {height: 10},
shadowOpacity: 0.3,
borderWidth: 2,
borderColor: '#FFFFFF',
zIndex: 99,
},
});
Screenshot:
Home screen
Detail screen
How do I hide it completely? Thanks!
Actually your tab bar is hiding but as you place this on above of the tabs that's why you still able to see after making tabBarVisible = false you also have to hide it manually with styles while making tabBarVisible = false, Check the route and apply styles dynamically.
pass style object to tabBarOptions
tabBarOptions: {
style: {
opacity: 0
}
}
Or this may also work
tabBarOptions: {
style: {
top: 50
}
}
Edit: By looking into your code I had to change some structure of your navigator and now it's working in the snack, You were rendering stack inside the tabs but it should be tabs inside a stack.
Link to snack
I just faced the same issue when I used the custom image.
Here is my solution.
You have to find the index of the Tab you want to hide. Then you can handle the opacity of the tab bar by checking the index.
tabBarOptions={{
style: {...styles.navigator, opacity: routeIndex === 2 ? 0 : 1},
}}
const HomeTab = createBottomTabNavigator();
export const HomeTabScreens = ({route}) => {
const routeIndex = route.state.index; // 2 is the screen that I want to hide.
...
}
you can add focused prop in tabBarIcon and apply style accordingly :
tabBarIcon: ({focused) => {
<Image
source={InstaCircleIcon}
style={[
{width: 87, height: 87},
focused && {width: 0, height: 87},
]}
/>
}
Complete example
<Tab.Screen
name="Addpost"
component={Addpost}
options={{
tabBarLabel: '',
tabBarIcon: ({focused}) => (
<TouchableOpacity style={[{top: -30, borderRadius: 50}]}>
<Image
source={InstaCircleIcon}
style={[
{width: 87, height: 87},
focused && {width: 0, height: 87},
]}
/>
</TouchableOpacity>
),
tabBarVisible: false,
}}
/>
I have a View with few form elements and a button (TouchableHighlight). On clicking the button, an Activity Indicator should be shown as an overlay to the existing view. The Activity Indicator should be centered within the page and the existing view should be slightly blurred to indicate overlay. I tried different options but could not get it to work.
render() {
const { username, password } = this.state;
return (
<View style={styles.container}>
<View style={styles.group}>
<Text style={styles.text}>Username:</Text>
<TextInput
style={styles.input}
onChangeText={this.handleUserNameChange.bind(this)}
value={username}
underlineColorAndroid="transparent"
/>
</View>
<View style={styles.group}>
<Text style={styles.text}>Password:</Text>
<TextInput
style={styles.input}
secureTextEntry={true}
onChangeText={this.handlePasswordChange.bind(this)}
value={password}
underlineColorAndroid="transparent"
/>
</View>
<TouchableHighlight
style={styles.button}
onPress={this.handleLogin.bind(this)}>
<Text style={styles.buttonText}>Logon</Text>
</TouchableHighlight>
</View>
);
}
Existing styles:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#F5FCFF',
marginTop: 60
},
group: {
alignItems: 'flex-start',
padding: 10
},
input: {
width: 150,
padding: 2,
paddingLeft: 5,
borderColor: 'gray',
borderWidth: 1
},
text: {
padding: 0
},
button: {
width: 150,
backgroundColor: '#2299F2',
padding: 15,
marginTop: 20,
borderRadius: 5
},
buttonText: {
textAlign: 'center',
color: '#fff',
fontSize: 24
},
});
I need to an ActivityIndicator to the above View, overlay the view, and center the ActivityIndicator.
For this to work, you'd need to absolute position it, and render it after the elements that should be underneath the overlay:
loading: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
}
Then simply compose it into the render method conditionally, based on a loading state. I am going to assume this.handleLogin sets some sort of loading state already.
Make sure it's rendered last so it takes precedence.
...
{this.state.loading &&
<View style={styles.loading}>
<ActivityIndicator size='large' />
</View>
}
Here is a complete example using create react native app.
import React from 'react';
import {StyleSheet, ActivityIndicator, View} from "react-native";
export default class Example extends React.Component {
constructor(props) {
super(props);
this.state = {}
render() {
return (
<View
style={{flex: 1}}
>
//Add other content here
{this.state.loading &&
<View style={styles.loading}>
<ActivityIndicator/>
</View>
}
</View>
);
}
}
showLoading() {
this.setState({loading: true})
}
hideLoading() {
this.setState({loading: false})
}
const styles = StyleSheet.create({
loading: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
opacity: 0.5,
backgroundColor: 'black',
justifyContent: 'center',
alignItems: 'center'
}
})
You can use StyleSheet.absoluteFill to shorten code.
Add this to your render:
<View style={styles.container}>
//... other code here
{this.state.loading && <View
style={{
...StyleSheet.absoluteFill,
justifyContent: 'center',
alignItems: 'center',
}}>
<ActivityIndicator />
</View>}
</View>
Improvement:
You can also create a Loading component:
Loading.js
import React from 'react';
import {View, ActivityIndicator, StyleSheet} from 'react-native';
export const Loading = ({theme = 'white', size = 'large'}) => {
const color = theme === 'white' ? '#00bdcd' : '#fff';
return (
<View
style={{
...StyleSheet.absoluteFill,
justifyContent: 'center',
alignItems: 'center',
}}>
<ActivityIndicator size={size} color={color} />
</View>
);
};
Then use it anywhere you want
<View style={styles.container}>
//... other code here
// remember to import Loading component
{this.state.loading && <Loading />}
</View>
You can build a nice overlay using the activity indicator component by also leveraging the modal capabilities like Sanaur suggests.
For example you can use the below functional component. You can control it's visibility through the show prop that you can tie to a state in your screen.
An example that you can adapt to your needs.
const ModalActivityIndicator = props => {
const {
show = false,
color = "black",
backgroundColor = "white",
dimLights = 0.6,
loadingMessage = "Doing stuff ..."
} = props;
return (
<Modal transparent={true} animationType="none" visible={show}>
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: `rgba(0,0,0,${dimLights})`
}}
>
<View
style={{
padding: 13,
backgroundColor: `${backgroundColor}`,
borderRadius: 13
}}
>
<ActivityIndicator animating={show} color={color} size="large" />
<Text style={{ color: `${color}` }}>{loadingMessage}</Text>
</View>
</View>
</Modal>
);
};
and in your screen, in the render's return, just add it there as a child (please ignore the rest of the code, I put it there for context).
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={{ padding: 13, flex: 1}}>
<ModalActivityIndicator show={screenIsWaiting} />
<View
style={{
where screenIsWaiting is just a state, for example
const [screenIsWaiting, setScreenIsWaiting] = useState(false);
To test it you can add a button somewhere,
<Button
title="TestButton"
onPress={async () => {
setScreenIsWaiting(true);
await sleep(5000);
setScreenIsWaiting(false);
...
}}
/>
where sleep is a function defined as
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
I found the sleep() idea on stackoverflow on another post.
You can of course also define the
<ModalActivityIndicator show={screenIsWaiting} ... />
only once in your App's root component and trigger it's display and props via a global state container like redux.
There is a library available for this react-native-loading-spinner-overlay.
You can simply install it using
npm install react-native-loading-spinner-overlay --save
and can import into your project using
import Spinner from 'react-native-loading-spinner-overlay';
Here is how to use it
<Spinner
//visibility of Overlay Loading Spinner
visible={this.state.loading}
//Text with the Spinner
textContent={'Loading...'}
//Text style of the Spinner Text
textStyle={styles.spinnerTextStyle}
/>
STEP 1:
Create the component for the spinner:
export const OverlaySpinner = () => {
return (
<View style={styles.spinnerView}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
};
STEP 2:
Create the style for the spinner view (using zIndex is very important to make sure the view is over everything on the screen):
spinnerView: {
position: "absolute",
zIndex: 1,
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#F5FCFF88",
},
STEP 3:
Make the initial state for the spinning component:
const [showSpinner, setshowSpinner] = useState(true);
STEP 4:
Use the component and don't forget to import it (don't forget to dismiss the keyboard on submit)
{showSpinner && <OverlaySpinner />}
I suppose you should use Modal to overlay activity indicator. Following is an example:
<Modal
transparent={true}
animationType={'none'}
visible={loading}
onRequestClose={() => {console.log('close modal')}}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator
animating={loading} />
</View>
</View>
</Modal>
Add in view of loading
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
set in View of Activity Indicator
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
Here my code for a functional component for anyone looking to achieve this with nativebase as design system. useColorScheme is another hook I use for detecting dark mode.
import { Flex, Spinner } from "native-base"
import React from "react"
import useColorScheme from "../../hooks/useColorScheme"
export default function Loading() {
const colorScheme = useColorScheme()
return (
<Flex
position="absolute"
alignItems="center"
justifyContent="center"
top={0}
left={0}
right={0}
bottom={0}
backgroundColor={colorScheme === "dark" ? "coolBlack.500" : "white"}
>
<Spinner size="lg" color={colorScheme === "dark" ? "white" : "coolBlack.500"} />
</Flex>
)
}