React Native Developer

Saturday, February 20, 2021

Apple Music UI PanResponder-Animation-Tutoria In React Native || React Native Music Player App UI Tutorial | React Native Tutorial

PanResponder :


PanResponder works in combination with the Animated API to help generate complex UI movements. The example below contains an animated View part that can be freely dragged across the screen


Example



import React, {useState, useEffect, useRef} from 'react';
import {
  View,
  Text,
  Dimensions,
  Animated,
  PanResponder,
  ScrollView,
  Image,
  TouchableOpacity,
from 'react-native';
const {width, height} = Dimensions.get('window');
import Icon from 'react-native-vector-icons/Ionicons';
const App = (props) => {
  const onPressPlay = () => {
    setIsPlay(!isPlay);
  };
  const [isPlay, setIsPlay] = useState(true);
  const [isScrollEnabled, setIsScrollEnabled] = useState(false);
  const animation = useRef(new Animated.ValueXY({x: 0, y: height - 90}))
    .current;
  const scrollOffset = 0;

  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: (evt, gestureState) => {
        if (
          (isScrollEnabled && scrollOffset <= 0 && gestureState.dy > 0) ||
          (!isScrollEnabled && gestureState.dy < 10)
        ) {
          console.log('isScrollEnabled', isScrollEnabled);
          console.log('!isScrollEnabled', !isScrollEnabled);
          console.log('scrollOffset', scrollOffset);
          console.log('gestureState DY', gestureState);
          return true;
        } else {
          return false;
        }
      },

      onPanResponderGrant: (evt, gestureState) => {
        animation.extractOffset();
      },
      onPanResponderMove: (evt, gestureState) => {
        animation.setValue({x: 0, y: gestureState.dy});
      },
      onPanResponderRelease: (evt, gestureState) => {
        if (gestureState.moveY > height - 120) {
          Animated.spring(animation.y, {
            toValue: 0,
            tension: 1,
            useNativeDriver: false,
          }).start();
        } else if (gestureState.moveY < 120) {
          console.log('gestureState', gestureState);
          Animated.spring(animation.y, {
            toValue: 0,
            tension: 1,
            useNativeDriver: false,
          }).start();
        } else if (gestureState.dy < 0) {
          setIsScrollEnabled(false);
          Animated.spring(animation.y, {
            toValue: -height + 120,
            tension: 1,
            useNativeDriver: false,
          }).start();
        } else if (gestureState.dy > 0) {
          setIsScrollEnabled(false);

          Animated.spring(animation.y, {
            toValue: height - 120,
            tension: 1,
            useNativeDriver: false,
          }).start();
        }
      },
    }),
  ).current;

  const animatedHeight = {
    transform: animation.getTranslateTransform(),
  };

  const animatedImageHeight = animation.y.interpolate({
    inputRange: [0, height - 90],
    outputRange: [20032],
    extrapolate: 'clamp',
  });

  const animatedSongTitleOpacity = animation.y.interpolate({
    inputRange: [0, height - 500, height - 90],
    outputRange: [001],
    extrapolate: 'clamp',
  });

  const animatedImageMarginLeft = animation.y.interpolate({
    inputRange: [0, height - 90],
    outputRange: [width / 2 - 10010],
    extrapolate: 'clamp',
  });
  const animatedSongDetailsOpacity = animation.y.interpolate({
    inputRange: [0, height - 500, height - 90],
    outputRange: [100],
    extrapolate: 'clamp',
  });
  const animatedHeaderHeight = animation.y.interpolate({
    inputRange: [0, height - 90],
    outputRange: [height / 390],
    extrapolate: 'clamp',
  });
  console.log('panResponder:;', panResponder.panHandlers);
  return (
    <View style={{flex: 1, backgroundColor: '#f8f8ff'}}>
      <Animated.View
        {...panResponder.panHandlers}
        style={[
          animatedHeight,
          {
            position: 'absolute',
            left: 0,
            right: 0,
            zIndex: 10,
            backgroundColor: '#fff',
            height: height,
          },
        ]}>
        <ScrollView
          scrollEnabled={isScrollEnabled}
          scrollEventThrottle={16}
          onScroll={(event) => {
            scrollOffset = event.nativeEvent.contentOffset.y;
          }}>
          <Animated.View
            style={{
              height: animatedHeaderHeight,
              borderTopWidth: 1,
              borderTopColor: '#ebe5e5',
              flexDirection: 'row',
              alignItems: 'center',
            }}>
            <View style={{flex: 4, flexDirection: 'row', alignItems: 'center'}}>
              <Animated.View
                style={{
                  height: animatedImageHeight,
                  width: animatedImageHeight,
                  marginLeft: animatedImageMarginLeft,
                }}>
                <Image
                  style={{flex: 1, width: null, height: null}}
                  source={{
                    uri:
                      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTfCrFGpWG5cxEH5GpVjNU8wFutQebq-sn1ww&usqp=CAU',
                  }}
                />
              </Animated.View>
              <Animated.Text
                style={{
                  opacity: animatedSongTitleOpacity,
                  fontSize: 18,
                  paddingLeft: 10,
                }}>
                I Love You song
              </Animated.Text>
            </View>

            <Animated.View
              style={{
                opacity: animatedSongTitleOpacity,
                flex: 1,
                flexDirection: 'row',
                justifyContent: 'space-around',
              }}>
              <TouchableOpacity onPress={() => onPressPlay()}>
                <Icon
                  name={isPlay ? 'play-outline' : 'pause-outline'}
                  size={32}
                />
              </TouchableOpacity>
            </Animated.View>
          </Animated.View>
          <Animated.View
            style={{
              height: animatedHeaderHeight,
              opacity: animatedSongDetailsOpacity,
            }}>
            <View
              style={{
                flex: 1,
                alignItems: 'center',
                justifyContent: 'flex-end',
              }}>
              <Text style={{fontWeight: 'bold', fontSize: 22}}>
                Music Player Is (On)
              </Text>
              <Text style={{fontSize: 18, color: '#fa95ed'}}>
                despacito despacito
              </Text>
            </View>

            <View
              style={{height: 40, width: width, alignItems: 'center'}}></View>
            <View
              style={{
                flex: 0.5,
                flexDirection: 'row',
                alignItems: 'center',
                justifyContent: 'space-around',
              }}>
              <TouchableOpacity>
                <Icon name={'play-skip-back-outline'} size={32} />
              </TouchableOpacity>
              <TouchableOpacity onPress={() => onPressPlay()}>
                <Icon
                  name={isPlay ? 'play-outline' : 'pause-outline'}
                  size={32}
                />
              </TouchableOpacity>
              <TouchableOpacity>
                <Icon name={'play-skip-forward-outline'} size={32} />
              </TouchableOpacity>
            </View>
          </Animated.View>
        </ScrollView>
      </Animated.View>
    </View>
  );
};
export default App;


onResponder* callbacks. For example, the config object would look like:

    • onMoveShouldSetPanResponder: (e, gestureState) => {...}
    • onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
    • onStartShouldSetPanResponder: (e, gestureState) => {...}
    • onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
    • onPanResponderReject: (e, gestureState) => {...}
    • onPanResponderGrant: (e, gestureState) => {...}
    • onPanResponderStart: (e, gestureState) => {...}
    • onPanResponderEnd: (e, gestureState) => {...}
    • onPanResponderRelease: (e, gestureState) => {...}
    • onPanResponderMove: (e, gestureState) => {...}
    • onPanResponderTerminate: (e, gestureState) => {...}
    • onPanResponderTerminationRequest: (e, gestureState) => {...}
    • onShouldBlockNativeResponder: (e, gestureState) => {...}




5 comments: