React Native ImageBackground in FlatList header - javascript

I am testing my app on android and I have seen that when I scroll down and then to the top of my flatlist, the header (which have an ImageBackground component) is blank (it seems that dissapears when it is not visible in the screen) and then fades in. I don't have this error on iOS, only in android.
Here is the code of the FlatList:
<FlatList
ref={scrollRef}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
colors={[
colors.primary,
colors.pink,
colors.strawberry,
colors.pig,
]}
tintColor={colors.primary}
onRefresh={handleRefresh}
/>
}
ListHeaderComponent={
<View style={styles.headerContainer}>
<Header
uploadProgress={uploadProgress}
onConfigurationButtonPress={handleConfigurationDisplay}
/>
</View>
}
ListFooterComponent={<Tab />}
style={[styles.container, { backgroundColor: colors.white }]}
/>
As you can see, in my flatlist I have two components, a tab in the footer, and a custom component called Header, which code is:
...
<ImageBackground
source={{ uri }}
blurRadius={Platform.OS === "ios" ? 40 : 10}
style={styles.container}
>
<View
style={[styles.overlay, { backgroundColor: colors.transparentWhite }]}
/>
{children}
</ImageBackground>
...
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
},
overlay: {
...StyleSheet.absoluteFillObject,
},
});
Any ideas? Thanks.

Related

ScrollView not working in react-native app, content disappears when attempting to add flex and flexGrow

for some reason a ScrollView in one of my components isn't working despite working in every other component I've implemented it in. Attempting to implement solutions to similar problems seems to just make the content I want displayed disappear.
I'm expecting to have a scrollable list of sample restaurant dishes. I created some dummy data to pass in for now but noticed it didn't scroll after reaching the end of the phone screen.
const testFoods = [
{
title: "test",
description: "Lorem Ipsum",
price: "$7.77",
image: "dummyLink",
},
// Same as above but 4 more times, didn't want to clog up the description
];
export default function MenuItems() {
return (
<ScrollView showsVerticalScrollIndicator={false}>
{testFoods.map((food, index) => (
<View key={index}>
<View style={styles.menuItemStyle}>
<FoodDetails food={food} />
<FoodImage food={food} />
</View>
</View>
))}
</ScrollView>
);
}
const FoodDetails = (props) => (
<View style={{ width: 240, justifyContent: "space-evenly" }}>
<Text style={styles.titleStyle}>{props.food.title}</Text>
<Text>{props.food.description}</Text>
<Text>{props.food.price}</Text>
</View>
);
const FoodImage = (props) => (
<View>
<Image
source={{ uri: props.food.image }}
style={{
width: 100,
height: 100,
borderRadius: 8,
}}
/>
</View>
);
const styles = StyleSheet.create({
menuItemStyle: {
flexDirection: "row",
justifyContent: "space-between",
margin: 20,
},
titleStyle: {
fontSize: 19,
fontWeight: "600",
},
});
The result is like so
Result with code above
The Header component with the sample restaurant image is a separate component by the way.
I have more data that can't be seen as for whatever reason the screen refuses to scroll. I'm using my actual phone for the tests but the result is the same when I use an emulator, scrolling doesn't work. After looking online I thought I would try adding a parent View with flex: 1 and a flexGrow: 1 to contentContainerStyle inside the ScrollView like so.
export default function MenuItems() {
return (
<View style={{ flex: 1 }}>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={{ flexGrow: 1 }}
>
{testFoods.map((food, index) => (
<View key={index} style={styles.menuItemStyle}>
<FoodDetails food={food} />
<FoodImage food={food} />
</View>
))}
</ScrollView>
</View>
);
}
But that only resulted in the content disappearing. Reloading the app didn't change anything either Result after trying above code
Attempting to use a FlatList had the same result. I've also read that having percentage based styling values on height for any of the children components can make the scrolling stop working but all my components don't utilize such. Oddly enough when I change the styling on the outer view to height: 400, I'm able to get the scrolling to work but this is very sloppy and will likely only work on phone screens similar to mine. I know the ScrollView component is working fine, as when I add "horizontal" to it the scrolling works just fine and I'm able to scroll to the last item in the dataset. Obviously all the content is horizontal now though. After adding horizontal too ScrollView, scrolling works fine horizontally
Any ideas? Could it be some part of my styling I'm not noticing? I'm unable to test this on IOS so I'm not sure if it's an Android specific problem, would be strange though as scrolling worked fine in my other components.
Here's also the Header component code just in case it could be anything in there, although It shouldn't be.
const testImage =
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Restaurant_N%C3%A4sinneula.jpg/800px-Restaurant_N%C3%A4sinneula.jpg";
const testTitle = "Sample Restaurant";
const testDescription = "Thai · Comfort · $$ · 🎫 · 4 ⭐ (217+)";
export default function About() {
return (
<View>
<RestaurantImage image={testImage} />
<RestaurantTitle title={testTitle} />
<RestaurantDescription description={testDescription} />
</View>
);
}
const RestaurantImage = (props) => (
<Image source={{ uri: props.image }} style={{ width: "100%", height: 180 }} />
);
const RestaurantTitle = (props) => (
<Text
style={{
fontSize: 29,
fontWeight: "600",
marginTop: 10,
marginHorizontal: 15,
}}
>
{props.title}
</Text>
);
const RestaurantDescription = (props) => (
<Text
style={{
marginTop: 10,
marginHorizontal: 15,
fontWeight: "400",
fontSize: 15.5,
}}
>
{props.description}
</Text>
);
Wrap your card with TouchableOpacity.
<TouchableOpacity activeOpacity={0} key={index} style={styles.menuItemStyle}>
<FoodDetails food={food} />
<FoodImage food={food} />
</TouchableOpacity>
I hope this thing will work.

Add BackgroundImage to ScrollView in React-Native for JavaScript

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>

Not able to access the absolute position view in react-native android

I have a component called MDropDowlList which render the following view :
MDropDownList.js
render() {
return (
<View>
<View
style={{
backgroundColor: '#fff',
position: 'absolute',
left: 0,
right: 0,
top: 0,
maxHeight: 200,
}}
>
{
this.props.searchable && (
<TextInput
style={{ zIndex: 198 }}
onChangeText={(text) => this.search(text)}
/>
)
}
<FlatList
data={this.state.data}
keyboardShouldPersistTaps="always"
nestedScrollEnabled={true}
contentContainerStyle={{ zIndex: 199 }}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<TouchableHighlight
key={index.toString()}
style={{
padding: 10,
backgroundColor: '#fff',
}}
underlayColor="#5897fb"
onPress={() => this.props.handleOnPress(item)}
>
<MText size={18}>{item}</MText>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
Then I have called this component to another component called MDropDown which render method is as below :
MDropDown.js
render() {
return (
<View style={{ marginVertical: 5, zIndex: 3}}>
...
{/* Another components */}
...
{
this.state.displayDropDown && (
<MDropDownList data={this.props.data} searchable={this.props.searchable} handleOnPress={(item) => this.handleOnPress(item)} />
)
}
</View>
);
}
Now finally I called my MDropDown component in my main screen as follow :
render() {
return (
<KeyboardAvoidingView style={{ flex: 1, backgroundColor: Colors.bgGray }} behavior="padding">
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.container} keyboardShouldPersistTaps="always" nestedScrollEnabled={true}>
<View style={{ backgroundColor: '#fff', padding: 10 }}>
<MDropDown
label="Category"
placeholder="Select Category"
data={["test1", "test2", "test3", "test4", "test5"]}
onSelectItem={(selectedItem) => alert(selectedItem)}
searchable={true}
/>
</View>
</ScrollView>
</KeyboardAvoidingView>
)
}
But I am not able to access Flatlist item or TextInput of MDropDownList component. Even I am not able to focus TextInput available in MDropDownList.
Please help me what's going wrong here ???
Note : This issue is only on android, on ios it is working properly. On ios I am able to click flatlist item and focus TextInput as well as.
Tried using zIndex to the absolute view?
Add property of zIndex : 500 to the style.

React Native variables between JavaScript classes

I am trying to set up a navigation action using react-navigation but I am having trouble since I am using a FlatList and a Pure Component to render the items in the list. The list is rendering fine but when I try to add an onPress function to the TouchableHighlight I cannot call the normal navigate function because it does not know what the variable navigate means. I would like to keep the separate file for the Pure Component instead of moving it into the other class if possible.
Pure Component:
export default class Lot extends React.PureComponent {
render() {
return (
<TouchableHighlight
onPress={() => navigate('LotView')}
>
<View style={{ flex: 1, height: 150, alignItems: 'center', justifyContent: 'center' }}>
<View>
{this.props.active && (<Image source={images[this.props.index]} style={[styles.images]} />)}
</View>
</View>
</TouchableHighlight>
);
}
}
The following are in my App.js class.
FlatList
<FlatList
data={this.state.lots}
renderItem={({ item }) => <Lot {...item} />}
/>
Navigation screens
export const MyApp = StackNavigator({
Home: { screen: HomeScreen },
LotView: { screen: LotView },
});
Lot should be dummy component (should not have any external access)
export default class Lot extends React.PureComponent {
render() {
return (
<TouchableHighlight
onPress={this.props.onPress} // <== CHANGED
>
<View style={{ flex: 1, height: 150, alignItems: 'center', justifyContent: 'center' }}>
<View>
{this.props.active && (<Image source={images[this.props.index]} style={[styles.images]} />)}
</View>
</View>
</TouchableHighlight>
);
}
}
HomeScreen
<FlatList
data={this.state.lots}
renderItem={({ item }) => <Lot {...item} onPress={() => this.props.navigate('LotView')} />} //<== CHANGED
/>

Showing list empty message at the center of the screen in a FlatList using ListHeaderComponent

I am using React-Native version 0.43.0 which does not support ListEmptyComponent of FlatList. Hence I am using ListHeaderComponent to render a view when the list is empty,
import React, { Component } from 'react';
import { Text, View, StyleSheet,FlatList } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {
listData: []
}
}
render() {
return (
<View style={styles.container}>
<FlatList
renderItem={() => null}
data={this.state.listData}
ListHeaderComponent={() => (!this.state.listData.length?
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
: null)
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1
},
emptyMessageStyle: {
textAlign: 'center',
//My current hack to center it vertically
//Which does not work as expected
marginTop: '50%',
}
});
As you can see from the image the text is not centered vertically
Any idea how to center it vertically in a FlatList?
I have already tried applying justifyContent, alignItems etc but no use.
This is a link to the snack.expo - https://snack.expo.io/S16dDifZf
Hope this will help you
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
disableVirtualization={false}
data={this.state.data}
renderItem={this.renderItem}
ListEmptyComponent={this.renderEmptyContainer()}
/>
}
/>
Place your UI in the renderEmptyContainer() method and boom, Empty container will show up whenever your list is empty
They fixed ListEmptyComponent in this pr https://github.com/facebook/react-native/pull/18206. But they will ship in 0.56.
UPDATE: Checkout the official doc ListEmptyComponent
You can add a style to the FlatList.
const styles = StyleSheet.create({
container: {
flex:1
},
listStyle: {
justifyContent: 'center'
},
emptyMessageStyle: {
textAlign: 'center',
}
});
render() {
return (
<View style={styles.container}>
<FlatList style={styles.listStyle}
renderItem={() => null}
data={this.state.listData}
ListHeaderComponent={() => (!this.state.listData.length ?
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
: null)}
/>
</View>
);
}
This will center the items in the list, when the list is not empty. You may have to apply another style (when the list is not empty), if you don't prefer the non empty style.
Link to snack.expo
Another option - without changing FlatList style - conditionally rendering FlatList based on this.state.listData.length
render() {
return (
<View style={styles.container}>
{
this.state.listData.length?
(<FlatList
renderItem={() => null}
data={this.state.listData}
/>)
:
(
<View style={styles.emptyListStyle}>
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
</View>
)
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1
},
emptyListStyle: {
flex: 1,
justifyContent: 'center'
},
emptyMessageStyle: {
textAlign: 'center',
}
});
This is the snack.expo
You must combine props ListEmptyComponent with contentContainerStyle={{flex:1}} flex:1 will set the maximal height in the container and will allow you to center vertically. ie:
<FlatList
...
contentContainerStyle={customers.length === 0 && styles.centerEmptySet}
ListEmptyComponent={<EmptySetCustomer />}
/>
Note that you must set a condition to remove flex:1 when list is not empty. To allow scroller.
Hope it will help.
This resolve for me.
<FlatList
contentContainerStyle={{ flexGrow: 1,
justifyContent: "center",
alignItems: "center"}}
disableVirtualization={false}
data={this.state.data}
renderItem={this.renderItem}
ListEmptyComponent={this.renderEmptyContainer()}
/>
}
/>
As a temporary workaround you can conditionally set a style to the contentContainer to center only the empty set like this
<FlatList
contentContainerStyle={customers.length === 0 && styles.centerEmptySet}
data={customers}
renderItem={({ item, index }) => (
/// Your item here
)}
keyExtractor={(item, index) => {
return String(index);
}}
ListEmptyComponent={<EmptySetCustomer />}
/>
And styles like this
centerEmptySet: { justifyContent: 'center', alignItems: 'center', height: '100%' }
Then in 2-3 weeks we can update to 0.56 and remove the workaround
<FlatList
keyExtractor={(item) => item.id}
data={flatListItems}
ListEmptyComponent={<View style= {styles.EmptytextHeader}><Text style={styles.EmptyMassage}>No data found</Text></View>}
renderItem={({ item }) => {
return <View><Text>add Your Data</Text></View>
/>
}}
/>
const styles = StyleSheet.create({
EmptytextHeader: {
flex:1,
justifyContent:'center',
alignItems:'center'
},
EmptyMassage: {
color:'red',
fontWeight: '700',
fontSize: 16,
fontStyle: 'normal',
},
});
its working

Categories

Resources