ReactNative

[ReactNatvie] react-native-image-viewing를 사용하여 이미지 슬라이드안에 동영상도 넣을 수 있을까?

HA젠옹 2023. 11. 3. 01:07
반응형

React Native에서 이미지 슬라이드 모달창을 쉽게 만들 수 있는 방법이 react-native-image-viewing를 사용하는 방법이 있다.

npm install react-native-image-viewing

yarn add react-native-image-viewing

해당 라이브러리를 설치 후 

import ImageView from "react-native-image-viewing";

// 이미지 항목 배열
const imageItems = [
  { uri: "IMG_URL" },
  { uri: "IMG_URL" },
  // ...
];

// 모달 열기 상태 관리
const [isImageViewVisible, setImageViewVisible] = useState(false);
const [selectedImageIndex, setSelectedImageIndex] = useState(0);

// 모달 뷰 열기
const openImageView = (index) => {
  setSelectedImageIndex(index);
  setImageViewVisible(true);
};

return (
  <View>
    {/* 이미지 목록 */}
    {imageItems.map((item, index) => (
      <TouchableHighlight
        key={index}
        onPress={() => openImageView(index)}
      >
        <Image source={{ uri: item.uri }} style={{ width: 200, height: 200 }} />
      </TouchableHighlight>
    )}

    {/* 이미지 모달 */}
    <ImageView
      images={imageItems.map((item) => ({ uri: item.uri }))}
      imageIndex={selectedImageIndex}
      visible={isImageViewVisible}
      onRequestClose={() => setImageViewVisible(false)}
    />
  </View>
);

예시로 해당 형식으로 진행 시 이미지리스트에 있는 이미지를 선택 하면 모달이 호출이 된다.

또한 react-native-image-viewing 라이브러리를 활용하여 가져온 배열안에 있는 img를 전부 호출하여 슬라이드형식으로 확인이 가능해진다.

 

하지만 난 여기서 이미지뿐만이 아닌 동영상도 함께 보여주고 싶어 조사를 해보니

 

react-native-image-viewing 해당 라이브러리는 이미지 관련 라이브러리 사용이 불가능하다는 내용을 확인 할 수 있었다.

 

어째서일까??

 

고민 끝에 내가 생각한 이론적인 부분으로 결국 react-native-image-viewing 해당 라이브러리는 슬라이드 모달이며, 해당 라이브러리에서 가져오는 데이터는 url 주소일텐데 어째서 이미지만 호출이 되는걸까? 라는 의문점을 가지게 되었고, 시도를 위해 동영상 url 주소를 같이 받아서 출력을 해본 결과

 

예상대로 동영상 또한 출력이 되는걸 확인 할 수 있었다. 하지만, 무한 로딩으로 정상적으로 출력이 안되는걸 확인 되었으며 어떻게 해결할 방법이 없을까 찾는 와중 react-native-video 라이브러리를 함께 사용하면 어떨까? 싶어 알아보니 

 

react-native-image-viewing 해당 라이브러리와 react-native-video 해당 라이브러리는 함께 사용이 가능하다는걸 알게 되었다.

 

그렇다면 우린 여기서 조금만 더 커스텀을 하여 사용한다면 문제가 없다는 결론을 마주할 수 있다.

npm install react-native-video

yarn add react-native-video

그럼 우선 추가적으로 필요한 react-native-video도 설치를 해준다.

 

import React, { useState } from 'react';
import { View, Text, SafeAreaView, Dimensions, TouchableHighlight } from 'react-native';
import ImageView from 'react-native-image-viewing';
import Video from 'react-native-video';

const App = () => {
  const { height, width } = Dimensions.get('window');

  const mediaItems = [
    { type: 'image', uri: 'https://example.com/image1.jpg' },
    { type: 'video', uri: 'https://example.com/video1.mp4' },
  ];

  const [mediaIndex, setMediaIndex] = useState(0);
  const [isModalVisible, setIsModalVisible] = useState(false);

  const openMediaModal = (index) => {
    setMediaIndex(index);
    setIsModalVisible(true);
  };

  const closeMediaModal = () => {
    setIsModalVisible(false);
  };

  const renderMediaItem = (item, index) => {
    if (item.type === 'image') {
      return (
        <TouchableHighlight key={index} onPress={() => openMediaModal(index)}>
          <Text>Image {index + 1}</Text>
        </TouchableHighlight>
      );
    } else if (item.type === 'video') {
      return (
        <TouchableHighlight key={index} onPress={() => openMediaModal(index)}>
          <Text>Video {index + 1}</Text>
        </TouchableHighlight>
      );
    }
    return null;
  };

  return (
    <SafeAreaView style={{ flex: 1, backgroundColor: '#333' }}>
      {mediaItems.map((item, index) => renderMediaItem(item, index))}
      <ImageView
        images={mediaItems.map((item) => ({ uri: item.uri }))}
        imageIndex={mediaIndex}
        visible={isModalVisible}
        onRequestClose={closeMediaModal}
        renderFooter={(currentImage) => {
          if (mediaItems[currentImage.index].type === 'video') {
            return (
              <View>
                <Video
                  source={{ uri: mediaItems[currentImage.index].uri }}
                  style={{ width, height: 250 }}
                  controls
                />
              </View>
            );
          }
          return null;
        }}
      />
    </SafeAreaView>
  );
};

export default App;

여기서 아까와 동일한 방법으로 진행을 하면 안된다.

 

우선 배열에 우린 img와 video를 구분하기 위해 type이라는 키값을 하나 제공을 해야하며,

 

해당 키값을 예외처리를 하여 video 일 경우 방금 설치한 react-native-video 라이브러리를 활용하여 이미지가 아닌 영상을 출력해줘야 한다.

 

그 후는 일반적인 방식과 동일하여 출력하는데 큰 문제는 없다고 본다.

 

하지만 글을 보시는 분들을 위해 더미 데이터를 만들어 보여주었지만, 필자의 경우 외부 데이터를 가져와 사용을 하고 있으며

또한, 동영상이 일반 서버에 업로드 된 동영상이 아닌 vimeo라는 영상을 출력해야 한다.

 

만약, 누군가 똑같이 vimeo 영상을 호출하는데 해당 내용을 참고 하여도 동영상이 출력이 되지 않고 무한로딩이 나타난다면 

우리는 체크 해야할 상황이 하나더 더 생긴다.

 

바로 권한 문제이다.

 

vimeo의 경우 해당 자체사이트에 영상이 업로드 되어 url에 넘버를 제공하여 영상을 확인할 수 있다.

 

그렇기 때문에 해당 영상을 사용하기 위해 키값을 받아 세팅을 해줘야하는데 여기서 권한 또한 세팅을 해줘야한다.

 

일반적으로 api 동영상 업로드를 위해 웹 권한만 받아둘 확률이 높기 때문에 만약 그러하다면 앱 권한 또한 세팅을 해줘야지만

 

해당 vimeo 영상이 정상적으로 출력되는걸 확인 할 수 있을 것이다.

 

참고로, 거창하게 글을 올렸지만 필자 또한 아직 vimeo에 대한 앱 권한을 받지 못하여 해당 부분은 확인을 못하여

 

추후 권한을 받은 뒤 해당 내용에 대해서는 추가적으로 글을 올릴 수 있도록 하겠다.

 

#2023.11.03 추가내용

해당 내용에 대해 추가적으로 내용을 이어가보자면

 

해당 형식으로 작업을 할 경우 과연 우리가 원하는 결과가 나올 것인가?

 

사실상 슬라이드 모달 자체에서 이미지와 동영상은 직접적인 커스텀을 하지 않는 이상 하기 힘들다 라는 결론이 났다.

 

위에 제공한 코드를 사용하더라도 결국 사용한 속성값은 footer 영역으로 다들 알다싶이 footer란 하단에 생성된 내용이라 생각할 수 있다.

 

즉, 해당 코드를 활용한다면 예외처리로 video일 경우 footer 내용을 보여주기 때문에 주 기능인 슬라이드는 위로 가며, 하단에 동영상이 출력이 된다. 

 

여기서 문제!

 

일반적으로 동영상을 전체영역을 활용하여 보여주는걸 선호 할텐데 그렇다면 footer 영역이 메인 영역을 잡아먹을 경우 어떻게 될까?

 

정답은 고유기능 슬라이드는 사용하지 못하고 푸터가 상단에 보여준다.

 

그렇다면 우리가 원하는 슬라이드 모달안에 이미지와 동영상을 같이 보여주는게 맞는것인가?

 

나는 아니라고 본다.

 

결국 다른 라이브러리를 찾아보게 되었고, 그 중에서 react-native-image-zoom-viewer와 react-native-image-pan-zoom example, react-native-image-zoom-viewer 등 여러가지 라이브러리를 사용하였지만

 

결과는 동영상을 사용 못한다 또는 위와 같은 현상이 나타났다.

 

그렇다면 정말 슬라이드 모달에 이미지와 동영상은 함께 사용할 수 없는걸까?

 

이것 또한 불가능한 소리는 아니다. 위에 말한 것 처럼 직접 커스텀을 하여 작업을 하면 된다.

 

어차피 라이브러리들 또한 결국 기초적인 환경에서 만들어진 내용이다.

 

그렇다면 어떤 형식으로 하면 될까?

 

쉽게 생각하여 앱이 아닌 웹이라고 생각해보자.

 

방법은 생각보다 간단하다. 일단 슬라이드 환경을 만들어주기 위해 슬라이드 기능을 넣어줄 것이다.

 

방법은 다양할 것이며, 흔히 사용하는 Swiper 라이브러리를 사용해도 무관하다.

 

여기서 우린 모달을 하나 만든 뒤 해당 기능을 안에 넣을 것이다.

 

그럼 이미 슬라이드 모달의 형성은 구현된 것이다.

 

그 후 이미지와 동영상 태그를 넣어주면 그만이다. 

 

당연 if문을 활용하여 예외처리를 해주긴 해야할테지만, 순수 퍼블리싱이라면 필요는 없어 보인다.

 

그럼 이미 우린 슬라이드모달안에 이미지와 동영상을 함께 사용할 수 있게 작업을 한 것이다.

 

그 후에는 적절하게 필요한 기능을 추가하면 된다.

 

이걸 반대로 앱에서도 똑같이 적용한다고 생각하면 간단해 보일 것이다.

 

해당 내용에 대한 실험 결과는 당연히 성공하였다. 하지만 같이 작업하는 사람한테 이론적인 설명을 주며 해보라고 하였기 때문에 내 수중에는 작업 코드가 없다.

 

그렇기 때문에 이글을 보고 믿을지 말지는 본인들이 결정하면 된다.

 

#추가

추가적으로 Vimeo 관련하여 ReactNative에서 사용해본 결과 난 video 라이브러리를 활용하여 테스트를 해보았지만, 안타깝게도 정상적으로 영상은 송출되지 않았다.

 

 

react-native-vimeo-iframe

React Native Vimeo Iframe is a library to render Vimeo videos in a React Native app. This component allows you to embed a Vimeo video in your app and have full access to the Vimeo player JS API (more information https://developer.vimeo.com/player/js-api)..

www.npmjs.com

 

그렇게 찾아낸 라이브러리가 react-native-vimeo-iframe 이다.

npm i react-native-vimeo-iframe

yarn add react-native-vimeo-iframe

 

해당 라이브러리를 설치 후 비메오에서 제공하는 키값과 영상 id 값을 넣어주면 동영상은 문제없이 실행이 된다. 

  const videoCallbacks = {
    timeupdate: (data: any) => console.log('timeupdate: ', data),
    play: (data: any) => console.log('play: ', data),
    pause: (data: any) => console.log('pause: ', data),
    fullscreenchange: (data: any) => console.log('fullscreenchange: ', data),
    ended: (data: any) => console.log('ended: ', data),
    controlschange: (data: any) => console.log('controlschange: ', data),
  };

  return (
     <Vimeo
        videoId={'712158285'}
        params={'api=1&autoplay=0'}
        handlers={videoCallbacks}
      />
  )

 

 

반응형