본문 바로가기

react-native

[RN] react-native Webview 로딩 이미지

 

react-native Webview 환경에서 화면이 이동될 때 노출되는 로딩 이미지를 애니메이션으로 구현.

나는 이미지 3개를 순차적으로 같이 노출 시키기 위해 zoom과 흐릿한 효과를 추가 했다.

 

 

애니메이션을 사용하기 위해 react-native-animatable 설치

npm install --save react-native-animatable

 

 

LoadingScreen.js

import React, {useEffect, useState} from 'react';
import {View, StyleSheet, Image} from 'react-native';
import * as Animatable from 'react-native-animatable';

/* 로딩이미지 */
const BlurryImage = ({source, delay}) => {
  const [isImgLoaded, setIsImgLoaded] = useState(false);
  useEffect(() => {
    setTimeout(() => {
      setIsImgLoaded(true);
    }, delay); // 이미지가 나타나기 전 0.5초 동안 흐릿한 효과를 위해 딜레이 적용
  }, []);

  return (
    <Animatable.View
      style={[
        styles.item,
        styles.imageContainer,
        {opacity: isImgLoaded ? 1 : 0},
      ]} // 초기에는 투명도를 0으로 설정하여 숨김
      animation={{
        from: {opacity: 0, scale: 0.7},
        to: {opacity: isImgLoaded ? 1 : 0, scale: isImgLoaded ? 1 : 0.8},
      }}
      duration={2500}
      delay={delay} // delay 속성 적용
      iterationCount="infinite" // 애니메이션 반복 설정
      useNativeDriver>
      <Image source={source} style={styles.image} />
    </Animatable.View>
  );
};

const LoadingScreen = () => {
  return (
    <View style={styles.loadingWrap}>
      <View style={styles.loading_n}>
        <View style={styles.itemWrap}>
          <BlurryImage source={require('/assets/ico_loading1.png')} delay={0} />
          <BlurryImage
            source={require('/assets/ico_loading2.png')}
            delay={350}
          />
          <BlurryImage
            source={require('/assets/ico_loading3.png')}
            delay={700}
          />
        </View>
      </View>
    </View>
  );
};

//로딩바 스타일
const styles = StyleSheet.create({
  loadingWrap: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(255, 255, 255, 0.6)',
  },
  loading_n: {zIndex: 999},
  itemWrap: {
    position: 'relative',
    alignItems: 'center',
    justifyContent: 'center',
  },
  item: {position: 'absolute', alignItems: 'center', justifyContent: 'center'},
  imageContainer: {alignItems: 'center', justifyContent: 'center'},
});
export default LoadingScreen;

 

 

Home.js

import LoadingScreen from '/screens/LoadingScreen';

...

function Home() {
  const [isLoaded, setIsLoaded] = useState(false);
  
  // 페이지 로딩 구분
  onLoadProgress = event => {
    if (event.nativeEvent.progress === 1) {
      setIsLoaded(false);
    } else {
      setIsLoaded(true);
    }
  };

	return (
    <>
    	<SafeAreaView style={{flex: 1}}>
    		<ScrollView contentContainerStyle={{flex: 1}}>
    			<WebView
    				source={{uri: webviewUri}}
    				...
    				onLoadProgress={onLoadProgress}
    			/>

				{isLoaded && (
				/* 로딩화면 */
					<LoadingScreen />
				)}
			</ScrollView>
		</SafeAreaView>
	</>
    );
}

 

기존에는 onNavigationStateChange(IOS), onLoadProgress(Android)로 구분 해서 사용 했는데 어느 순간 IOS에서도 onNavigationStateChange가 먹지 않는 현상이 발생... 원인은 모르겠다

그래서 그냥 onLoadProgress로 통합했다.