Reputation: 8261
I am trying to build a ReactNative Application with an animated button. The problem is that this animation does not work correctly the first time after the App is started. There is some white flickering. But after the animation ran wrong the first time everything works as expected:
I have already tried to preload the image in several ways, but without any success.
This is my minimal working example, note that if there are several different images the flickering occurs if a new image is loaded (e.g. I have two blue buttons and after I tapped the first one, the second one will work fine, but if I then tap an orange button it once again flickers for the first time, at least if I have not tapped another orange button after app start.):
import React, { Component } from 'react';
import {StyleSheet, Text, TouchableWithoutFeedback, View, Image, ScrollView,
Button, BackHandler} from 'react-native';
export default class Touchables extends Component {
constructor(props) {
super(props);
this.state = {alarm1: (<Image source={require("./assets/alarmoff.png")}
style={styles.imageButton}/>),
}
}
componentWillMount(){
//trying to preload all Images, but it does not help.
(<Image source={require("./assets/alarmon.png")} style=
{styles.imageButton}/>)
}
render() {
return (
<ScrollView style={styles.contentContainer}>
<View style={{flex: 3, flexDirection: 'row'}}>
<View style={styles.container}>
<TouchableWithoutFeedback onPressIn={() => this.setState({alarm1:
<Image source={require("./assets/alarmon.png")} style={styles.imageButton}/>})} onPressOut={() => this.setState({alarm1: <Image source={require("./assets/alarmoff.png")} style={styles.imageButton}/>})}>
<View style={styles.button}>
{this.state.alarm1}
</View>
</TouchableWithoutFeedback>
<Text style={styles.text}>This button flickers on first click. Restart App completly to see the issue. Reloading is not enough.</Text>
</View>
</View>
<View>
<Button
onPress={() => BackHandler.exitApp()}
title="Exit App"
color="#841584"
accessibilityLabel="Android only I guess."
/>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 2,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 30
},
button: {
backgroundColor: '#fff',
borderRadius: 20,
padding: 10,
marginBottom: 20,
shadowColor: '#303838',
shadowOffset: { width: 0, height: 5 },
shadowRadius: 10,
shadowOpacity: 0
},
contentContainer: {
paddingVertical: 20,
flex: 1,
backgroundColor: '#fff',
},
text:{
color: '#000',
marginBottom: 30
},
imageButton: {
flex: 1,
width: 240,
height: 200,
marginBottom: -15,
marginTop: 10,
resizeMode: 'cover'
}
});
So my question is how can I stop the image from flickering after app start?
The full version of the little demo app I have build to show my problem is available on my Github Repository
Upvotes: 8
Views: 13997
Reputation: 11
A stupid way:
<ImageBackground
defaultSource={require('./ui/pay0.png')}
source={require('./ui/pay0.png')}
style={{flex: 1, position: 'relative', zIndex: 9999, elevation: 5}}
/>
{/* Cache the remaining pictures to prevent flickering */}
<ImageBackground
source={require('./ui/pay1.png')}
style={{position: 'absolute', width: 1, height: 1}}
/>
Upvotes: 1
Reputation: 11
For anyone who still have this problem : this is another way to fix
<Image
source={{ uri: your_path }}
defaultSource={{ uri: your_path }}
resizeMode="cover"
style={{width: 100,height: 100}} />
Upvotes: 1
Reputation: 11
It was causing flickering issues when I put the Image component in a FlatList ListHeaderComponent component
In order to solve the issue I added useCallBack hook
const ListComponent = useCallBack(() => {
// your code
}, [])
ListHeaderComponent={ListComponent}
For me it solved the flickering issue
Upvotes: 1
Reputation: 180
For me, it was causing flickering issues when I put the Image component in a FlatList ListHeaderComponent component. So,
Code causing flickering:
ListHeaderComponent={HeadComponent}
The HeadComponent was basically inside render
and had the code const HeadComponent = () => { return (<Image...
Code that fixed flickering:
ListHeaderComponent={this.renderHeader}
The renderHeader
is a function that returned the same thing as HeadComponent
using code renderHeader () { return (<Image...
Hope this helps someone.
Upvotes: 2
Reputation: 2176
If you are using expo, you can use Asset.loadAsync
. See: https://docs.expo.io/versions/latest/sdk/asset.
In App.js
, I like to wait for all static assets to be loaded before showing any screen.
Upvotes: -2
Reputation: 8261
Well I have a workaround (sort of..).
In my componentDidMount()
I do now set the button to its pressed state, wait for some time until the image is displayed and scaled, and then I set the state to off again, like so:
componentDidMount(){
this.setState({alarm1: <Image source={require("./assets/alarmon.png")} style={styles.imageButton}/>})
setTimeout(()=>{this.setState({alarm1: <Image source={require("./assets/alarmoff.png")} style={styles.imageButton}/>})}, 1000);
}
I tried to lower the timeout to less than a second, but then on my old (and slow) phone the flickering started again on first press after app load.
This obviously leads to the button state beeing changed after the app loaded, but if all buttons flicker once after app start, that is better than every button flickering on first press in my opinion.
I would however be glad if anybody could tell me the real way, how to resolve this.
Upvotes: 0
Reputation: 2545
There may be a performance issue while loading different resolution images. You can use https://github.com/DylanVann/react-native-fast-image module to load images.
you can add and link it as below
# Install
yarn add react-native-fast-image
# Automatic linking. (other linking methods listed below)
react-native link react-native-fast-image
after that u can import it and use it using like below example
import FastImage from 'react-native-fast-image'
const YourImage = () =>
<FastImage
style={styles.image}
source={{
uri: 'https://unsplash.it/400/400?image=1',
headers:{ Authorization: 'someAuthToken' },
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.contain}
/>
I copied this example from that repo. you can find documentation also there. Try it. It will increase image loading performance. Then most probably flickering issue will be resolved.
Upvotes: 3