Kurs React Native · Moduł 6: Zdjęcia, kamera i dźwięk

expo-av - Audio i Video

2 min czytania ·
W tej lekcji5

Odtwarzaj audio i video w swojej aplikacji!

Instalacja

npx expo install expo-av

Odtwarzanie video

import { Video, ResizeMode } from 'expo-av';
import { useState, useRef } from 'react';

function VideoPlayer() {
  const videoRef = useRef<Video>(null);
  const [status, setStatus] = useState<any>({});

  return (
    <View style={styles.container}>
      <Video
        ref={videoRef}
        style={styles.video}
        source={{ uri: 'https://example.com/video.mp4' }}
        useNativeControls
        resizeMode={ResizeMode.CONTAIN}
        isLooping
        onPlaybackStatusUpdate={(status) => setStatus(() => status)}
      />

      <View style={styles.controls}>
        <Pressable
          onPress={() =>
            status.isPlaying
              ? videoRef.current?.pauseAsync()
              : videoRef.current?.playAsync()
          }
        >
          <Ionicons
            name={status.isPlaying ? 'pause' : 'play'}
            size={32}
          />
        </Pressable>
      </View>
    </View>
  );
}

Odtwarzanie audio

import { Audio } from 'expo-av';

function AudioPlayer() {
  const [sound, setSound] = useState<Audio.Sound>();
  const [isPlaying, setIsPlaying] = useState(false);

  const playSound = async () => {
    const { sound } = await Audio.Sound.createAsync(
      require('@/assets/audio/ocean.mp3')
    );
    setSound(sound);
    await sound.playAsync();
    setIsPlaying(true);
  };

  const pauseSound = async () => {
    if (sound) {
      await sound.pauseAsync();
      setIsPlaying(false);
    }
  };

  // Cleanup
  useEffect(() => {
    return sound
      ? () => {
          sound.unloadAsync();
        }
      : undefined;
  }, [sound]);

  return (
    <Pressable onPress={isPlaying ? pauseSound : playSound}>
      <Ionicons name={isPlaying ? 'pause' : 'play'} size={48} />
    </Pressable>
  );
}

Audio w tle

import { Audio } from 'expo-av';

async function setupAudio() {
  await Audio.setAudioModeAsync({
    playsInSilentModeIOS: true,
    staysActiveInBackground: true,
    shouldDuckAndroid: true,
  });
}

Nagrywanie audio

import { Audio } from 'expo-av';

function AudioRecorder() {
  const [recording, setRecording] = useState<Audio.Recording>();
  const [recordingUri, setRecordingUri] = useState<string>();

  const startRecording = async () => {
    try {
      const permission = await Audio.requestPermissionsAsync();
      if (!permission.granted) return;

      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        playsInSilentModeIOS: true,
      });

      const { recording } = await Audio.Recording.createAsync(
        Audio.RecordingOptionsPresets.HIGH_QUALITY
      );

      setRecording(recording);
    } catch (error) {
      console.error('Błąd nagrywania:', error);
    }
  };

  const stopRecording = async () => {
    if (!recording) return;

    await recording.stopAndUnloadAsync();
    const uri = recording.getURI();
    setRecordingUri(uri ?? undefined);
    setRecording(undefined);
  };

  return (
    <View>
      <Pressable
        onPress={recording ? stopRecording : startRecording}
        style={[styles.recordButton, recording && styles.recording]}
      >
        <Ionicons name={recording ? 'stop' : 'mic'} size={32} color="white" />
      </Pressable>

      {recordingUri && <Text>Nagrano: {recordingUri}</Text>}
    </View>
  );
}

expo-av obsługuje wszystkie potrzeby audio/video!

Kod do tej lekcji: App.tsx
import React, { useState, useEffect } from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { Audio } from 'expo-av';

export default function App() {
  const [sound, setSound] = useState<Audio.Sound>();
  const [isPlaying, setIsPlaying] = useState(false);

  const playSound = async () => {
    // TODO: utwórz dźwięk za pomocą Audio.Sound.createAsync(...)
    //   - przekaż { uri: 'https://example.com/ocean.mp3' } jako source
    //   - rozpakuj wynik: const { sound } = await Audio.Sound.createAsync(...)
    //   - zapisz go: setSound(sound)
    //   - uruchom odtwarzanie: await sound.playAsync()
    //   - ustaw setIsPlaying(true)

  };

  const pauseSound = async () => {
    if (sound) {
      await sound.pauseAsync();
      setIsPlaying(false);
    }
  };

  // Zwalnianie zasobu dźwięku przy odmontowaniu
  useEffect(() => {
    return sound ? () => { sound.unloadAsync(); } : undefined;
  }, [sound]);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Dźwięki Atlantydy</Text>
      <Pressable
        style={styles.button}
        onPress={isPlaying ? pauseSound : playSound}
      >
        <Text style={styles.buttonText}>{isPlaying ? 'Pauza' : 'Odtwórz'}</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#1a5276' },
  title: { color: '#aed6f1', fontSize: 20, marginBottom: 24 },
  button: { backgroundColor: '#2980b9', paddingVertical: 14, paddingHorizontal: 40, borderRadius: 8 },
  buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
});

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Który prop włącza natywne kontrolki w komponencie Video?

Zadania praktyczne w grze

  • Klikanie w kolejności

    Kliknij elementy tworzenia dźwięku:

  • Edytor kodu

    Uzupełnij kod Audio.Sound z play/pause.

Przydatne artykuły