React-native android images flashing on load - react-native

I am having trouble on Android where the images are flashing only on Android and I cannot seem to find a solution.
I have attached a video below to show the problem
Here is my Flatlist
<FlatList
ListEmptyComponent={_listEmptyComponent}
initialNumToRender={2}
keyExtractor={(item) => item.key}
renderItem={renderItem}
data={walletData}
contentContainerStyle={{ flexGrow: 1, justifyContent: 'flex-start', paddingBottom: 80, marginTop: 20 }}
style={{ padding: 5, marginTop: 40, backgroundColor: '#ffff' }} />
Here is my renderItem Function:
const renderItem = ({ item }: any) => { return (
<View style={{marginTop: 20}}>
<Card title={item.category} logo={item.logoImage} name={item.name} address={item.shortAddress} background={item.backgroundImage} Key={item.chainId} Stamps={item.schemes} Vouchers={item.vouchers} />
</View>
)
}
Here is the Card Image part:
<View style={styles.top}>
{/* Background image */}
{loading &&
<View style={{ justifyContent: 'center', flexDirection: 'row', width: '100%' }}>
<ActivityIndicator size="small" color="black" />
</View>
}
{
<FastImage
style={{
height: Dimensions.get('window').height / 4.5,
width: '100%',
borderRadius: 12
}}
onLoadStart={() => onLoading(true)}
onLoadEnd={() => onLoading(false)}
source={{
uri: background,
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.cover}>
{/* Logo image */}
<View style={styles.test} >
<Image
style={styles.imageTop2}
source={{ uri: logo }}
onLoadStart={() => onLoading(true)}
onLoadEnd={() => onLoading(false)}
/>
</View>
</FastImage>
}
</View>
Video Link: https://www.youtube.com/shorts/_v758YEg9iY

Some logic cause screen to rerender 2 times. iOS caches pre-loaded images and use cached images for the next rerender without refetch them.
Android doesn't cache t images and fetches them again for the next rerender which takes some milliseconds to be ready and results in flickering.
The solution is to avoid a second rerender or wait until all data fetching finishes before app render a FlatList.
Try to remove this state change.
...
onLoadStart={() => onLoading(true)}
onLoadEnd={() => onLoading(false)
...

Related

React Native mapbox gl zIndex not displaying as expected

I'm trying to build a LIVE map and I noticed that the zIndex of the react-native mapbox gl doesn't work when the render is in a different state. When you render something after, it stays underneath. Is there anyway for certain things to always be on top? For example, callback should always be on top no matter what.
<MapboxGL.MapView
style={{flex: 1}}
styleURL={'mapbox://styles/gigajungkyu/ckt962t3a19zh17pfq1sr7z3f'}
pitchEnabled={false}
rotateEnabled={false}>
<MapboxGL.PointAnnotation
id={'1'}
key={'1'}
style={{zIndex: 1}}
coordinate={[-122.849, 49.1]}>
<TouchableOpacity
style={{zIndex: 1}}
onPress={() => setDisplay((prevState) => !prevState)}>
<View
style={{width: 100, height: 100, backgroundColor: 'red'}}></View>
</TouchableOpacity>
<MapboxGL.Callout title={'You'} />
</MapboxGL.PointAnnotation>
{display && (
<MapboxGL.PointAnnotation
id={'2'}
key={'2'}
style={{zIndex: 99999999}}
coordinate={[-103.349, 49.1]}>
<TouchableOpacity style={{zIndex: 5}}>
<View
style={{
width: 100,
height: 100,
backgroundColor: 'blue',
}}></View>
</TouchableOpacity>
<MapboxGL.Callout title={'You'} />
</MapboxGL.PointAnnotation>
)}
</MapboxGL.MapView>

React Native: How to render a list further down a scrollview?

Good day,
I'm building a React Native app with expo and I have a list of photos that I need to render but further down the screen.
My problem is that I need a scrollview to render the content before, but I can't have a list inside a scrollview so I tried to put my flatlist just after the closing tag scrollview but now the flatlist renders mid-page and the above content is scrollable from mid page up.
What i'm trying to do is have a continued view from the top of the screen to the end of my flatlist.
I've tried setting the flex of my scrollview at 1 so it would take up all the screen but it doesn't.
Thank you for your help!!!
EDIT
renderFeed = (data) =>
<View style={{ marginTop: 25, marginLeft: 5 }}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('EditContact', { id: data.item.id })}>
<Image style={{ width: 300, height: 300, marginRight: 5 }}
source={{ uri: data.item.profile }}>
</Image>
</TouchableOpacity>
<Text style={{ color: '#fff', fontSize: 20, marginBottom: 10, marginTop: 10, marginLeft: 5, alignSelf: 'center' }}>{data.item.name}</Text>
</View>
render() {
return (
<View style={styles.container}>
<View>
// top of the page outside of scrollview
</View>
<ScrollView>
<View>
// some text and a horizontal flatlist that renders as
// expected
</View>
</ScrollView>
<FlatList
data={this.state.infoSource}
renderItem={item => this.renderFeed(item)}
keyExtractor={item => item.id.toString()}
numColumns={2}
/>
</View>
);
}
}

ScrollView with FlatList inside not working?

This is the code I have for the ScrollView
<ScrollView contentContainerStyle={{ flexGrow: 1 }} scrollEnabled>
<View style={{ maxHeight: 280 }}>
<FlatList
style={{ backgroundColor: '#eee' }}
data={suppliers}
keyExtractor={supplier => supplier}
renderItem={({ item, index }) => {
const style = index % 2 === 0 ? { backgroundColor: '#fff' } : null;
return (
<TouchableOpacity
style={{
...style,
height: height / 14,
borderColor: '#333',
borderWidth: 0.5,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Text style={{ fontSize: 14 }}>{item}</Text>
<Feather name="chevron-right" size={21} />
</TouchableOpacity>
);
}}
/>
</View>
</ScrollView>
The content of the FlatList is dynamic meaning that the length of the supplier array can change at anytime so I have a maxHeight and want it to simply be a list you can scroll through if the content extends the maxHeight. I have tried messing around with a lot of different things but nothing seems to work. You can see the outcome here
I get a list that is not scrollable.
In your first line remove the contentContainerStyle with flex-grow
your code
<ScrollView contentContainerStyle={{ flexGrow: 1 }} scrollEnabled>
change to
<ScrollView contentContainerStyle={{ }} scrollEnabled>
if you need flex then wrap the components with another view tag
For example
<ScrollView scrollEnabled>
<View style={{flexGrow: 1}}>
<FlatList/>
</View>
</ScrollView>
It worked for me.

Horizontal Flatlist Re-Render changes ListHeaderComponent

I'm banging my head on this one. I am using a horizontal flat list. And putting a view in ListHeaderComponent to act as padding. You can see it as a blue box in the first image below. That works great. Trouble is, when I refresh the flatlist from elsewhere in my app, the padding seems to break. See the blue box in image 2 below. Code below images. Any help appreciated.
OnLoad:
After props refresh:
<FlatList
ref={(ref) => { this.flatListRef = ref; }}
horizontal={true}
showsHorizontalScrollIndicator={false}
data={this.props.store.allBookData}
ListHeaderComponent={<View style={{ width: itemOffset / 2, height: 200, backgroundColor: 'blue' }}></View>}
ListFooterComponent={<View style={{ width: itemOffset /2 }}></View>}
renderItem={({ item }) =>(
<TouchableWithoutFeedback onPress={() => this.gotoBook(item)}>
<Animatable.View
animation={"fadeIn"}
easing={"ease-in-out"}
duration={320}
delay={240}
useNativeDriver={true}
style={[styles.bookItem, { width: itemWidth, height: itemHeight, marginTop: itemMarginTop, opacity: 1, marginRight: 24 }]}>
{/* cover */}
<View style={[styles.bookCover, { width: itemWidth, height: bookHeight, backgroundColor: global.setBookItemColor(item.color)}]}>
<View style={styles.bookBindingHolder}>
<View style={styles.bookBinding}></View>
</View>
<View style={styles.bookCoverPhotoHolder}>
<View style={styles.bookCoverPhoto}>
<FastImage style={styles.bookCoverFrame} resizeMode={'contain'} source={Images.coverFrameWithTape}/>
{(() => {
//display cover
if (item.cover == 'temp') {
//temp
return (<FastImage style={styles.bookCoverImg} resizeMode={'cover'} source={Images.tempCover} />)
}else{
//photo
return (
<FastImage
style={[styles.bookCoverImg, {opacity: 0.88}]}
resizeMode={'cover'}
source={{uri: item.cover}}>
</FastImage>
)
}
})()}
</View>
</View>
</View>
{/* title */}
<View style={styles.bookTitleHolder}>
<Text style={[global.TextStyles.h3, global.TextStyles.darkText, global.TextStyles.alignCenter]}>{item.title}</Text>
</View>
{/* count */}
<View style={styles.bookPhotoCountHolder}>
<View style={styles.bookPhotoCount}>
{(() => {
if (item.photoCount == global.maxPhotos){
var itemCount = 'Full'
}else{
var itemCount = item.photoCount + '/' + global.maxPhotos
}
return(
<Text style={[global.TextStyles.lightText, global.TextStyles.smallerLabel]}>{itemCount}</Text>
)
})()}
</View>
</View>
</Animatable.View>
</TouchableWithoutFeedback>
)}/>
It's hard to say where the problem comes from even though there's a good chance it comes from your itemOffset that you apply as width to your HeaderComponent.
However, I have the impression that you can make it easier to define paddings, instead of defining a header and footer component, you could simply apply paddings to the content of your list by passing to your list the props: contentContainerStyle
like that
<FlastList
...
contentContainerStyle={{
paddingHorizontal: itemOffset / 2
}}
/>
but I think you should look in your calcul of itemOffset

React Native Maps - Callout don't show image inside

I have a problem when I try to render an image inside the React Native Maps Callout.
The image does not render.
{this.state.database.map((route, idx) => {
if (route.Image) {
return (
<MapView.Marker
coordinate={{ latitude: Number.parseFloat(route.Latitude), longitude: Number.parseFloat(route.Longitude) }}
key={idx}
image={img_pin}
ref={(ref) => this.marker = ref}
>
<MapView.Callout tooltip style={{ flex: 1, backgroundColor: 'white' }}>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1 }}>
<Text style={styles.textCallout}>Latitude: {route.Latitude}</Text>
<Text style={styles.textCallout}>Longitude: {route.Longitude}</Text>
<Text style={styles.textCallout}>Status: <Icon name={route.Status === 1 ? 'checkmark-circle' : 'close-circle'} style={{ color: route.Status === 1 ? 'green' : 'red', fontSize: 16 }} /> </Text>
<Text style={styles.textCallout}>Velocidade: {route.Speed} km/h</Text>
</View>
<View style={{ margin: 5 }}>
<Image source={{ uri: `data:image/gif;base64,${route.Image}` }} style={{ width: 150, height: 100 }} />
</View>
</View>
</MapView.Callout>
</MapView.Marker>
);
}
})}
Image error don't render inside Callout
"react-native": "^0.57.8",
"react-native-maps": "^0.24.2",
Use Image inside Text component
<Text> <Image style={{ height: 100, width:100 }} source={{ ... }} resizeMode="cover" /> </Text>
Another workaround by using WebView. I think is the proper solution for this right now.
<View>
<WebView style={{ height: 100 , width: 230, }} source={{ uri: ... }} />
</View>
Make sure your route.image is in the form of url schema,
exampleData
source={{uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg=='}}
if correct,
GIF and WebP support on Android
When building your own native code, GIF and WebP are not supported by default on Android.
You will need to add some optional modules in android/app/build.gradle, depending on the needs of your app.
build.gradle:
dependencies {
// If your app supports Android versions before Ice Cream Sandwich (API level 14)
implementation 'com.facebook.fresco:animated-base-support:1.10.0'
// For animated GIF support
implementation 'com.facebook.fresco:animated-gif:1.10.0'
// For WebP support, including animated WebP
implementation 'com.facebook.fresco:animated-webp:1.10.0'
implementation 'com.facebook.fresco:webpsupport:1.10.0'
// For WebP support, without animations
implementation 'com.facebook.fresco:webpsupport:1.10.0'
}
Usage
<MapView.Callout tooltip={true} style={{ backgroundColor: 'white', height: contentHeight, width: contentWidth }}>
<View style={{ flexDirection: 'column' }}>
<View style={{ flex: 1 }}>
<Text style={styles.textCallout}>Latitude: {route.Latitude}</Text>
<Text style={styles.textCallout}>Longitude: {route.Longitude}</Text>
<Text style={styles.textCallout}>Status: <Icon name={route.Status === 1 ? 'checkmark-circle' : 'close-circle'} style={{ color: route.Status === 1 ? 'green' : 'red', fontSize: 16 }} /> </Text>
<Text style={styles.textCallout}>Velocidade: {route.Speed} km/h</Text>
</View>
<Image source={{ uri: `data:image/gif;base64,${route.Image}` }} style={{ width: 150, height: 100, resizeMode="cover" }} />
</View>
</MapView.Callout>