wcandillon / can-it-be-done-in-react-native

⚛️ 📺 Projects from the “Can it be done in React Native?” YouTube series
https://www.youtube.com/wcandillon
MIT License
4.05k stars 1.3k forks source link

How can fix the animated jumping view? #102

Open raviitsoft opened 4 years ago

raviitsoft commented 4 years ago

can you please help to fix the jumping animated view video-to-gif-converter ?

import React, {useRef} from 'react';
import {
  View,
  Text,
  StyleSheet,
  Platform,
  TextInput,
  Dimensions,
  Alert,
  FlatList,
} from 'react-native';

import Animated, {Easing} from 'react-native-reanimated';
import {
  withTimingTransition,
  onGestureEvent,
  withSpringTransition,
  delay,
} from 'react-native-redash';
import {TapGestureHandler, State} from 'react-native-gesture-handler';
const {width, height} = Dimensions.get('window');
import FontAwesome from 'react-native-vector-icons/FontAwesome5';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {Divider, List} from 'react-native-paper';
import RNGooglePlaces from 'react-native-google-places';

import {
  SCREEN_HEIGHT,
  SCREEN_WIDTH,
  LOCATION_SELECT_VIEW_HEIGHT,
} from '../../utils/constants';

const {
  Value,
  event,
  block,
  cond,
  eq,
  set,
  useCode,
  Clock,
  startClock,
  stopClock,
  debug,
  timing,
  clockRunning,
  interpolate,
  Extrapolate,
  SpringUtils,
} = Animated;

const runTiming = (clock, value, dest) => {
  const state = {
    finished: new Value(0),
    position: new Value(0),
    time: new Value(0),
    frameTime: new Value(0),
  };

  const config = {
    duration: 1000,
    toValue: new Value(0),
    easing: Easing.inOut(Easing.ease),
  };

  return block([
    cond(clockRunning(clock), 0, [
      set(state.finished, 0),
      set(state.time, 0),
      set(state.position, value),
      set(state.frameTime, 0),
      set(config.toValue, dest),
      startClock(clock),
    ]),
    timing(clock, state, config),
    cond(state.finished, debug('stop clock', stopClock(clock))),
    state.position,
  ]);
};

const Ravi = props => {
  const {
    navigation,
    mapData,
    onSetPickUpLocation,
    onSetPickOffLocation,
    onSetPredictions,
    onLocationSelected,
  } = props;

  const isOpen = useRef(new Animated.Value(0));
  const isOpenAnimation = withSpringTransition(isOpen.current, {
    ...SpringUtils.makeDefaultConfig(),
    overshootClamping: true,
    damping: new Animated.Value(20),
  });

  const buttonOpacity = interpolate(isOpenAnimation, {
    inputRange: [0, 1],
    outputRange: [1, 0],
  });

  const gestureState = useRef(new Animated.Value(State.UNDETERMINED));
  const gestureHandler = onGestureEvent({state: gestureState.current});

  const backArrowGestureState = useRef(new Animated.Value(State.UNDETERMINED));
  const backArrowGestureHandler = onGestureEvent({
    state: backArrowGestureState.current,
  });

  // useCode(
  //   () =>
  //     cond(eq(gestureState.current, State.END), [
  //       // set(gestureState.current, State.UNDETERMINED),
  //       set(buttonOpacity, runTiming(new Clock(), 1, 0)),
  //     ]),
  //   [gestureState.current],
  // );

  useCode(
    () =>
      cond(eq(gestureState.current, State.END), [
        cond(eq(isOpen.current, 0), set(isOpen.current, 1)),
        set(buttonOpacity, runTiming(new Clock(), 1, 0)),
      ]),
    [gestureState.current],
  );

  useCode(
    () =>
      cond(eq(backArrowGestureState.current, State.END), [
        set(gestureState.current, State.UNDETERMINED),
        set(buttonOpacity, runTiming(new Clock(), 0, 1)),
        delay(set(isOpen.current, 0), 250),
      ]),
    [backArrowGestureState.current],
  );

  const onPickUpQueryChange = text => {
    onSetPickUpLocation(text);
    RNGooglePlaces.getAutocompletePredictions(text)
      .then(places => {
        console.log(places, 'pickup');
        onSetPredictions(places, 'pickup');
      })
      .catch(error => console.log(error.message, 'sss'));
  };

  const onPickOffQueryChange = text => {
    onSetPickOffLocation(text);
    RNGooglePlaces.getAutocompletePredictions(text)
      .then(places => {
        console.log(places, 'pickoff');
        onSetPredictions(places, 'pickoff');
      })
      .catch(error => console.log(error.message, 'sss'));
  };

  const onSelectSuggestion = placeID => {
    RNGooglePlaces.lookUpPlaceByID(placeID)
      .then(results => {
        console.log(results, mapData.predictions.type, 'type');
        onLocationSelected(results, mapData.predictions.type);
      })
      .catch(error => console.log(error.message));
  };

  const keyExtractor = item => item.placeID;

  const renderItem = ({item}) => {
    return (
      <List.Item
        onPress={() => onSelectSuggestion(item.placeID)}
        title={item.primaryText}
        description={item.secondaryText}
        left={() => <Icon style={{...styles.leftIcon}} name="location-on" />}
        right={() => <Icon style={{...styles.leftIcon}} name="location-on" />}
      />
    );
  };

  const buttonY = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [100, 0],
    extrapolate: Extrapolate.CLAMP,
  });

  const bgY = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [-height / 3, 0],
    extrapolate: Extrapolate.CLAMP,
  });

  const textInputZindex = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [1, -1],
    extrapolate: Extrapolate.CLAMP,
  });

  const textInputOpacity = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [1, 0],
    extrapolate: Extrapolate.CLAMP,
  });

  const textInputTransY = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [0, 50],
    extrapolate: Extrapolate.CLAMP,
  });

  const sideMenuOpacity = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [0, 1],
    extrapolate: Extrapolate.CLAMP,
  });

  const sideMenutransY = interpolate(buttonOpacity, {
    inputRange: [0, 1],
    outputRange: [-60, 0],
    extrapolate: Extrapolate.CLAMP,
  });

  return (
    <>
      <Animated.View
        style={{
          top: Platform.select({ios: 40, android: 20}),
          width: 40,
          backgroundColor: '#fff',
          padding: 10,
          marginLeft: 10,
          // borderRadius: 10,
          shadowOffset: {width: 10, height: 10},
          shadowColor: '#CBCBCB',
          shadowOpacity: 1,
          elevation: 3,
          ...Platform.select({
            ios: {
              zIndex: 99,
            },
          }),
          transform: [{translateY: sideMenutransY}],
          opacity: sideMenuOpacity,
        }}>
        <FontAwesome
          name="bars"
          size={24}
          backgroundColor="#fff"
          color="#707070"
          onPress={() => navigation.openDrawer()}
        />
      </Animated.View>

      <Animated.View
        style={{
          height: height / 4,
          backgroundColor: 'white',
          justifyContent: 'flex-end',
          ...StyleSheet.absoluteFillObject,
          top: null,
          opacity: buttonOpacity,
          transform: [{translateY: buttonY}],
        }}>
        <TapGestureHandler {...gestureHandler}>
          <Animated.View
            style={{
              ...styles.button,
              backgroundColor: '#2E71DC',
              opacity: buttonOpacity,
              transform: [{translateY: buttonY}],
            }}>
            <Text style={{fontSize: 20, fontWeight: 'bold', color: 'white'}}>
              SIGN IN WITH FACEBOOK
            </Text>
          </Animated.View>
        </TapGestureHandler>
      </Animated.View>

      <Animated.View
        style={{
          backgroundColor: 'white',
          zIndex: textInputZindex,
          opacity: textInputOpacity,
          transform: [{translateY: textInputTransY}],
          // height: height / 3,
          ...StyleSheet.absoluteFill,
          bottom: null,
          justifyContent: 'center',
        }}>
        <View style={{flexDirection: 'row'}}>
          <Animated.View style={{...styles.backArrow, flex: 0.13}}>
            <TapGestureHandler {...backArrowGestureHandler}>
              <Animated.View>
                <FontAwesome name="arrow-left" size={24} />
              </Animated.View>
            </TapGestureHandler>
          </Animated.View>
          <View style={{flex: 1, marginTop: 20}}>
            <View style={{...styles.mainView}}>
              <View style={{...styles.cricleView}} />
              <View style={[{...styles.viewText}]}>
                <Text style={[{...styles.titleText}]}>Pickup location</Text>
                <View
                  style={{
                    flexDirection: 'row',
                  }}>
                  <View style={[{flex: 1}]}>
                    <TextInput
                      style={{
                        color: '#000',
                        paddingVertical: 1,
                      }}
                      placeholder="pickup location"
                      // value={mapData?.pickUpLocation}
                      // onChangeText={onPickUpQueryChange}
                      underlineColorAndroid={'transparent'}
                    />
                  </View>
                </View>
              </View>
            </View>
            <Divider
              style={{
                borderColor: '#9B9B9B',
                borderWidth: 0.5,
                marginTop: 10,
                marginBottom: 10,
                marginLeft: 40,
              }}
            />
            <View style={{...styles.mainView}}>
              <View style={[{...styles.iconView}]}>
                <FontAwesome
                  name="map-marker-alt"
                  size={16}
                  color={'#F5A623'}
                />
              </View>
              <View style={[{...styles.viewText}]}>
                <Text style={[{...styles.titleText}]}>Drop Off</Text>
                <View
                  style={{
                    flexDirection: 'row',
                  }}>
                  <View style={[{flex: 1}]}>
                    <TextInput
                      style={{
                        color: '#000',
                        paddingVertical: 1,
                      }}
                      placeholder="Location"
                      // value={mapData?.pickOffLocation}
                      // onChangeText={onPickOffQueryChange}
                      underlineColorAndroid={'transparent'}
                      autoFocus
                    />
                  </View>
                  <View style={[{...styles.imageView2}]}>
                    <FontAwesome
                      name="map-marked-alt"
                      size={16}
                      color={'#3AE1FE'}
                    />
                  </View>
                </View>
              </View>
            </View>
          </View>
        </View>
      </Animated.View>
      <Animated.View
        style={{
          backgroundColor: 'white',
          zIndex: textInputZindex,
          opacity: textInputOpacity,
          transform: [{translateY: textInputTransY}],
          // height: height / 2,
          ...StyleSheet.absoluteFill,
          top: LOCATION_SELECT_VIEW_HEIGHT + 20,
          justifyContent: 'center',
        }}>
        <FlatList
          data={mapData.predictions.data}
          renderItem={renderItem}
          keyExtractor={keyExtractor}
          showsVerticalScrollIndicator={false}
          contentContainerStyle={{flexGrow: 1}}
        />
      </Animated.View>
    </>
  );
};

export default Ravi;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  searchResultsWrapper: {
    top: LOCATION_SELECT_VIEW_HEIGHT + 60,
    position: 'absolute',
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    backgroundColor: '#fff',
  },
  button: {
    backgroundColor: 'white',
    height: 70,
    marginHorizontal: 20,
    borderRadius: 35,
    alignItems: 'center',
    justifyContent: 'center',
    marginVertical: 5,
  },
  backArrow: {
    justifyContent: 'flex-start',
    top: Platform.select({ios: 40, android: 20}),
    left: 10,
    right: 0,
  },
  mainView: {flexDirection: 'row', marginHorizontal: 10},
  cricleView: {
    backgroundColor: '#3AE1FE',
    borderRadius: 12,
    width: 12,
    height: 12,
    justifyContent: 'center',
    alignItems: 'center',
    marginHorizontal: 5,
    marginVertical: 8,
  },
  iconView: {
    marginHorizontal: 5,
    marginVertical: 8,
  },
  viewText: {
    flexDirection: 'column',
    flex: 0.85,
    justifyContent: 'center',
    marginLeft: 10,
  },
  titleText: {
    color: '#222',
    fontSize: 14,
    fontFamily: 'OpenSans-Regular',
    marginVertical: 5,
  },
  imageView2: {alignSelf: 'flex-end', flex: 0.1},
});
raviitsoft commented 4 years ago

I think something is wrong in useCode Block. Can you please help me?