Я новичок в React Native, но у меня проблемы с решением этой проблемы.
Желаемое поведение компонента Recorder
- начинать запись звука при нажатии TouchableOpacity
, и продолжайте запись, пока она не будет отпущена, после чего запись остановится. В основном цель состоит в том, чтобы заставить его вести себя как запись видео Snapchat.
Однако у меня возникают проблемы, когда запись очень короткая. Для создания экземпляра / начала записи звука требуется некоторое время, поэтому, если кнопка будет отпущена до того, как это произойдет, сработает функция OnPressOut
. Проблема в том, что этот OnPressOut
прервет OnPressIn
, который выбрасывает все из строя.
По сути, мне интересно, есть ли способ гарантировать, что OnPressIn
завершится до OnPressOut
запускается. Как я уже сказал, полный RN noob, так что извините, если это очевидное исправление. Я напортачил с InteractionManager
, но независимо от того, что это за поведение сохранилось. В любом случае, вот компонент и журнал быстрого нажатия, как я описывал, спасибо!
import React, {Component} from 'react';
import {View, TouchableOpacity, Text, ActivityIndicator, InteractionManager} from 'react-native';
import { Audio } from 'expo-av';
import * as Permissions from 'expo-permissions';
import * as FileSystem from 'expo-file-system';
import styles from './styles.js'
class Recorder extends Component {
constructor(props) {
super(props);
this.state = { recording: new Audio.Recording(),
isRecording: false };
this.recordingSettings = JSON.parse(JSON.stringify(Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY));
}
async stopRecording(){
console.log('STOP RECORDING ENTERED')
try {
this.setState({isRecording: false});
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false,
staysActiveInBackground: true,
})
await this.state.recording.stopAndUnloadAsync();
const info = await FileSystem.getInfoAsync(this.state.recording.getURI());
this.props.handlePress(info.uri.replace('file://',''))
} catch (error) {
if (this.state.recording != null) {
await this.state.recording.stopAndUnloadAsync();
this.setState({recording: null, isRecording: false})
}
console.log(error)
} finally{
console.log('STOP RECORDING EXITED')
}
}
async startRecording(){
console.log('START RECORDING ENTERED')
try {
this.setState({isRecording: true});
resp = await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false,
staysActiveInBackground: true,
})
this.state.recording.setOnRecordingStatusUpdate(null);
this.setState({recording: null})
var recording = new Audio.Recording();
await recording.prepareToRecordAsync();
recording.setOnRecordingStatusUpdate(this._updateScreenForRecordingStatus);
this.setState({recording: recording});
await this.state.recording.startAsync();
} catch (error) {
if (this.state.recording != null) {
await this.state.recording.stopAndUnloadAsync();
recording = null
this.setState({recording: null, isRecording: false})
}
console.log(error)
} finally{
console.log('START RECORDING EXITED')
}
}
async componentDidMount(){
await Permissions.askAsync(Permissions.AUDIO_RECORDING)
}
render() {
if (this.state.isRecording){
buttonStyle = styles.captureBtnInternal;
recordingMessage = 'Recording...'
}
else if (this.props.isMatching){
recordingMessage = 'Getting your matches...'
}
else if (this.props.isUploading){
recordingMessage = 'Uploading song...'
}
else{
buttonStyle = styles.captureBtn;
recordingMessage = 'Press and hold to record'
}
return (
<View style = {styles.alignCenter}>
<Text style = {styles.buttonText}>{recordingMessage}</Text>
{this.props.isMatching || this.props.isUploading
?
<ActivityIndicator/>
:
<TouchableOpacity
//Looks like if it goes too fast, onPressIn triggers, then onPressOut has to finish before before resuming, maybe ask SO?
onPressIn={() => this.startRecording()}
onPressOut={() => this.stopRecording()}
style={buttonStyle}>
</TouchableOpacity>
}
</View>
)
}
}
export default Recorder
LOG START RECORDING ENTERED
LOG STOP RECORDING ENTERED
LOG [Error: Prepare encountered an error: recorder not prepared.]
LOG START RECORDING EXITED
LOG [TypeError: null is not an object (evaluating 'this.state.recording.stopAndUnloadAsync')]
LOG STOP RECORDING EXITED