'React Native Flatlist Video custom Fullscreen

Has anyone here ever done a vertical video Flatlist with a button that makes the video fullscreen (not the native UI). If yes could you give some advice on how to achieve it? Should I make the video position absolute and make it go from top to bottom (tried but couldn't make it work in the Flatlist)? Should I have a hidden video component that shares the state with the one in the Flatlist? Thanks any guidance is appreciated



Solution 1:[1]

I would recommend using modal feature from react navigation package(check this)

with this package you can render your full screen video inside a separate view.

Solution 2:[2]

Here you go.

const App: () => Node = () => {
  const [popup, setPopup] = useState(false);
  return (
    <View style={{flex: 1, backgroundColor: 'aliceblue'}}>
      <FlatList
        data={[
          {title: '1', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
          {title: '2', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
        ]}
        renderItem={({item}) => (
          <Button title={item.title} onPress={() => setPopup(true)} />
        )}
      />
      {popup ? (
        <View
          style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            right: 0,
            left: 0,
            backgroundColor: '#00000050',
          }}>
          <View
            style={{
              backgroundColor: '#FFFFFF50',
              flex: 1,
              alignItems: 'center',
              justifyContent: 'center',
            }}>
            <Text>Use whatever library you want to use to play the video</Text>
          </View>
          <Button title="Close" onPress={() => setPopup(false)} />
        </View>
      ) : null}
    </View>
  );
};

I've built a sample that works for your requirement. Didn't do the Video stuff tho. Hope this helps.

See the above code in action

Updated code with Popup component

const Popup = ({videoUrl, onClose}) => {
  return (
    <View
      style={{
        position: 'absolute',
        top: 0,
        bottom: 0,
        right: 0,
        left: 0,
        backgroundColor: '#00000050',
      }}>
      <View
        style={{
          backgroundColor: '#FFFFFF50',
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}>
        <Text>{videoUrl}</Text>
      </View>
      <Button title="Close" onPress={onClose} />
    </View>
  );
};

const App: () => Node = () => {
  const [popup, setPopup] = useState(null);
  return (
    <View style={{flex: 1, backgroundColor: 'aliceblue'}}>
      <FlatList
        data={[
          {title: '1', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
          {title: '2', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
        ]}
        renderItem={({item}) => (
          <Button
            title={item.title}
            onPress={() =>
              setPopup({
                videoUrl: item.url,
              })
            }
          />
        )}
      />
      {popup != null ? (
        <Popup videoUrl={popup.videoUrl} onClose={() => this.setPopup(null)} />
      ) : null}
    </View>
  );
};

Solution 3:[3]

What is exact problem? You can't make it fullscreen by custom button? Or you want to make it fullscreen with your own custom layout? I guess first.

Not clean example, but should show how it works. https://snack.expo.dev/@valera.bitkovsky/react-native-flatlist-video-custom-fullscreen

import React from "react";
import { StyleSheet, Text, View, FlatList, Button } from "react-native";
import { Video, AVPlaybackStatus } from 'expo-av';

const VideoItem = React.forwardRef(({ url }, ref) => {
  const video = React.useRef(null);

  React.useImperativeHandle(ref, () => ({
    full: () => {
      video.current.presentFullscreenPlayer();
    }
  }), [])

  return  <Video
        ref={video}
        source={{
          uri: url,
        }}
        style={{
          width: 400,
          height: 200
        }}
        useNativeControls
        resizeMode="contain"
        isLooping
      />
});

function App() {
  const videoRefs = React.useRef([]);

  return (
    <View style={styles.app}>
      <FlatList
        data={[
          { url: "https://www.w3schools.com/html/mov_bbb.mp4" },
          { url: "https://www.w3schools.com/html/mov_bbb.mp4" }
        ]}
        renderItem={({ item, index }) => (<View>
          <VideoItem ref={ref => videoRefs.current[index] = ref} url={item.url} />
          <Button title="Fullscreen" onPress={() => videoRefs.current[index].full()} />
        </View>)}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  app: {
    marginTop: 50,
    marginHorizontal: "auto",
    maxWidth: 500
  }
});

export default App;

And if you want second varint, then you can just add state and change layout to absolute and do whatever you want.

enter image description here

UPD Regarding the aproach where we use absolute styles, seems that isn't possible, see this issue https://github.com/facebook/react-native/issues/29867

So, we still can use our custom controls, but probably we should use native fullscreen mode.

You can try use simple ScrollView, I know that it isn't optimazied for that very well, but absolute position should work

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Moein moeinnia
Solution 2
Solution 3