0

I have two screens, 1) Video calling screen 2) Chat screen.

I have implemented flip view using the library https://github.com/kevinstumpf/react-native-flip-view to show video calling screen as front screen, and when someone clicks on chat, flip the view and show chat as back screen.

I want to show a thumbnail camera view in chat and video calling screen with draggable view, it works on first load, however when I flip the screen, the PanGestureHandler stops working, although I can see the camera thumbnail view is still visible in the screen after the flip, however its position gets reset to top left corner (initial position) and drag is no more working.

Below is the code I am using.

import React, { Component } from 'react';
import { View, SafeAreaView, Dimensions, TouchableOpacity, Easing } from 'react-native';
import { moderateScale } from 'react-native-size-matters';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import { onGestureEvent } from 'react-native-redash';
import FlipView from 'react-native-flip-view-next';
import Animated from 'react-native-reanimated'
import ChatScreen from './../screens/ChatScreen';

const { Value, diffClamp, cond, set, eq, add } = Animated;
const DEVICE_WIDTH = Dimensions.get('window').width;
const DEVICE_HEIGHT = Dimensions.get('window').height;
const CARDWIDTH = moderateScale(120);
const CARDHEIGHT = moderateScale(160);
const withOffset = (value: Animated.Value<number>, state: Animated.Value<State>) => {
    const offset = new Value(0)
    return cond(eq(state, State.END), [set (offset, add(offset, value)), offset], add(offset, value));
};

export default class VideoSessionScreen extends Component {

    state = {
        isFlipped: false,
        ...
    }

    renderCameraThumbView = () => {
        const state = new Value(-1);
        const translationX = new Value(0);
        const translationY = new Value(0);
        const gestureHandler = onGestureEvent({state, translationX, translationY});
        const translateX = diffClamp(withOffset(translationX, state), 0, DEVICE_WIDTH-CARDWIDTH-moderateScale(30));
        const translateY = diffClamp(withOffset(translationY, state), 0, DEVICE_HEIGHT-CARDHEIGHT-moderateScale(55));
        return (
            <PanGestureHandler {...gestureHandler}>
                <Animated.View style={{ transform: [{translateX}, {translateY}], borderRadius: moderateScale(15), height: CARDHEIGHT, width: CARDWIDTH, overflow: 'hidden'}}>
                    {!this.state.isFlipped &&
                        <CameraLocalView enabled={true} style={{flex: 1}}/>
                    }
                    {this.state.isFlipped &&
                        <View style={{flex: 1, backgroundColor: '#111111'}}>
                            {Array.from(this.state.videoTracks, ([sid, trackId]) => {
                                return (
                                    <CameraRemoteView/>
                                )
                            })}
                        </View>
                    }
                </Animated.View>
            </PanGestureHandler>
        );
    };

    _renderFront() {
        return(
            <SafeAreaView style={{flex: 1, backgroundColor: '#111'}}>
                {'local' === this.state.cameraView &&
                    <>
                        <View style={{position: 'absolute', top: 0, right: 0, left: 0, bottom: 0, backgroundColor: 'red'}}>

                        </View>
                        <Animated.View style={{position: 'absolute', top: 0, right: 0, left: 0, bottom: 0, padding: moderateScale(15)}}>
                            {this.renderCameraThumbView()}
                        </Animated.View>
                    </>
                }
            </SafeAreaView>
        );
    }

    _renderBack() {
        return(
            <View style={{flex: 1}}>
                <ChatScreen
                    didPressBackBtn = {() => {
                        this.setState({
                            isFlipped: false
                        })
                    }}
                />
            </View>
        )
    }

    render() {
        return (
            <>
                <FlipView style={{flex: 1}}
                    front={this._renderFront()}
                    back={this._renderBack()}
                    isFlipped={this.state.isFlipped}
                    flipAxis="y"
                    flipEasing={Easing.out(Easing.ease)}
                    flipDuration={500}
                    perspective={1000}
                />
            </>
        );
    }
}

What could be the possible cause that PanGestureHandler does not work after I call this.state({{isFlipped: !this.state.isFlipped}}), how can I fix this?

Thanks.

Ibrahim Azhar Armar
  • 25,288
  • 35
  • 131
  • 207

1 Answers1

1

I had to redo and implement it the following way, which works perfectly now.

import React, { Component } from 'react';
import { moderateScale } from 'react-native-size-matters';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated'

const { cond, eq, add, set, Value, event } = Animated;
const CARDWIDTH = moderateScale(120);
const CARDHEIGHT = moderateScale(160);

export default class VideoSessionScreen extends Component {

    dragX = new Value(0);
    dragY = new Value(0);
    offsetX = new Value(0);
    offsetY = new Value(0);
    gestureState = new Value(-1);
    onGestureEvent = event([{
        nativeEvent: {
            translationX: this.dragX,
            translationY: this.dragY,
            state: this.gestureState,
        }
    }]);
    transX = cond(
        eq(this.gestureState, State.ACTIVE),
        add(this.offsetX, this.dragX),
        set(this.offsetX, add(this.offsetX, this.dragX)),
    );
    transY = cond(
        eq(this.gestureState, State.ACTIVE),
        add(this.offsetY, this.dragY),
        set(this.offsetY, add(this.offsetY, this.dragY)),
    );

    renderLocalCameraThumbView = () => {
        return (
            <PanGestureHandler maxPointers={1} onGestureEvent={this.onGestureEvent} onHandlerStateChange={this.onGestureEvent}>
                <Animated.View style={{transform: [{translateX: this.transX}, {translateY: this.transY}], borderRadius: moderateScale(15), height: CARDHEIGHT, width: CARDWIDTH, overflow: 'hidden'}}>
                    <CameraLocalView enabled={true} style={{flex: 1}}/>
                </Animated.View>
            </PanGestureHandler>
        );
    }

}
Ibrahim Azhar Armar
  • 25,288
  • 35
  • 131
  • 207
  • What is the real problem you have fixed? I have a similar problem. Image dragging only works once after update a trigger state (true or false) for re-rendering. – user938363 Aug 13 '20 at 05:44
  • Is it possible to add some sort of checks in the onGestureFunciton? Or can we only use the event directly? See this please https://stackoverflow.com/questions/64330969/stop-dragging-after-a-limit-has-reached –  Oct 13 '20 at 08:51