Giter VIP home page Giter VIP logo

apple-music-ui-pan-animation-tutorial's People

Contributors

nathvarun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

apple-music-ui-pan-animation-tutorial's Issues

function component swip down to close is not work please help bro...

MY CODE ๐Ÿ‘๐Ÿป

`import React, {useState, useEffect, useRef} from 'react';
import {
View,
Text,
StyleSheet,
Dimensions,
Animated,
PanResponder,
ScrollView,
Image,
Slider,
} from 'react-native';

const {width, height} = Dimensions.get('window');
import Icon from 'react-native-vector-icons/Ionicons';
const App = (props) => {
const [isScrollEnabled, setIsScrollEnabled] = useState(false);
const animation = new Animated.ValueXY({x: 0, y: height - 90});

const scrollOffset = 0;

const pan = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: (evt, gestureState) => {
if (
(isScrollEnabled && scrollOffset <= 0 && gestureState.dy > 0) ||
(!isScrollEnabled && gestureState.dy < 0)
) {
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) {
      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 [panResponder, setPanResponder] = useState(pan);
useEffect(() => {
setPanResponder(pan);
}, []);

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

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

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

const animatedImageMarginLeft = animation.y.interpolate({
inputRange: [0, height - 90],
outputRange: [width / 2 - 100, 10],
extrapolate: 'clamp',
});
const animatedSongDetailsOpacity = animation.y.interpolate({
inputRange: [0, height - 500, height - 90],
outputRange: [1, 0, 0],
extrapolate: 'clamp',
});
const animatedHeaderHeight = animation.y.interpolate({
inputRange: [0, height - 90],
outputRange: [height / 2, 90],
extrapolate: 'clamp',
});
const animatedBackgroundColor = animation.y.interpolate({
inputRange: [0, height - height],
outputRange: ['red', 'pink'],
extrapolate: 'extend',
});

return (
<Animated.View style={{flex: 1, backgroundColor: animatedBackgroundColor}}>
<Animated.View
{...panResponder.panHandlers}
style={[
animatedHeight,
{
position: 'absolute',
left: 0,
right: 0,
zIndex: 10,
backgroundColor: '#d3d3',
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,
}}>
Music Player Is (On)
</Animated.Text>

<Animated.View
style={{
opacity: animatedSongTitleOpacity,
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around',
}}>


</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'}}>
          <Slider
            style={{width: 300}}
            step={1}
            minimumValue={18}
            maximumValue={71}
            value={18}
          />
        </View>
        <View
          style={{
            flex: 2,
            flexDirection: 'row',
            alignItems: 'center',
            justifyContent: 'space-around',
          }}>
          <Icon name="md-rewind" size={40} />
          <Icon name="md-pause" size={50} />
          <Icon name="md-fastforward" size={40} />
        </View>
      </Animated.View>
    </ScrollView>
  </Animated.View>
</Animated.View>

);
};
export default App;`

Animation is not fluid on when run in create-react-native-app (build-ios) - runs perfectly fine on Expo

Hi,

Thanks for this great tutorial. I have followed along with the code and unfortunately found that the animation does not work as intended/is not smooth whatsoever when run on a native device (or simulator) - but works just as you would expect on expo.

As you can see from the gif, despite swiping up on the bar from the bottom a considerable distance - the height only increases by a small amount.

I have included the code below (the same as the tutorial).

import React, { Component } from 'react';
import {
    View,
    Text,
    Dimensions,
    Animated,
    Image,
    PanResponder,
    Slider,
    ScrollView,
} from 'react-native';

import Ionicons from "react-native-vector-icons/Ionicons";

const SCREEN_HEIGHT = Dimensions.get('window').height;
const SCREEN_WIDTH = Dimensions.get('window').width;

export default class AppleMusicUI extends Component {
    state = {
        isScrollEnabled: false,
    };
    componentWillMount() {
        this.scrollOffset = 0;

        this.animation = new Animated.ValueXY({ x: 0, y: SCREEN_HEIGHT - 90 });

        this.PanResponder = PanResponder.create({
            onMoveShouldSetPanResponder: (evt, gestureState) => {
                if (
                    (this.state.isScrollEnabled &&
                        this.scrollOffset <= 0 &&
                        gestureState.dy > 0) ||
                    (!this.state.isScrollEnabled && gestureState.dy < 0)
                ) {
                    return true;
                } else {
                    return false;
                }
            },
            onPanResponderGrant: () => {
                this.animation.extractOffset();
            },
            onPanResponderMove: (evt, gestureState) => {
                this.animation.setValue({ x: 0, y: gestureState.dy });
            },
            onPanResponderRelease: (evt, gestureState) => {
                if (gestureState.moveY > SCREEN_HEIGHT - 110) {
                    Animated.spring(this.animation.y, {
                        toValue: 0,
                        tension: 1,
                    }).start();
                } else if (gestureState.moveY < 110) {
                    Animated.spring(this.animation.y, {
                        toValue: 0,
                        tension: 1,
                    }).start();
                } else if (gestureState.dy < 0) {
                    this.setState({ isScrollEnabled: true });
                    Animated.spring(this.animation.y, {
                        toValue: -SCREEN_HEIGHT + 110,
                        tension: 1,
                    }).start();
                } else if (gestureState.dy > 0) {
                    this.setState({ isScrollEnabled: false });
                    Animated.spring(this.animation.y, {
                        toValue: SCREEN_HEIGHT - 110,
                        tension: 1,
                    }).start();
                }
            },
        });
    }
    render() {
        const animatedHeight = {
            transform: this.animation.getTranslateTransform(),
        };

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

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

        const animatedImageMarginLeft = this.animation.y.interpolate({
            inputRange: [0, SCREEN_HEIGHT - 90],
            outputRange: [SCREEN_WIDTH / 2 - 100, 10],
            extrapolate: 'clamp',
        });

        const animatedHeaderHeight = this.animation.y.interpolate({
            inputRange: [0, SCREEN_HEIGHT - 90],
            outputRange: [SCREEN_HEIGHT / 2, 90],
            extrapolate: 'clamp',
        });

        const animatedSongDetailsOpacity = this.animation.y.interpolate({
            inputRange: [0, SCREEN_HEIGHT - 500, SCREEN_HEIGHT - 90],
            outputRange: [1, 0, 0],
            extrapolate: 'clamp',
        });

        const animatedBackgroundColor = this.animation.y.interpolate({
            inputRange: [0, SCREEN_HEIGHT - 90],
            outputRange: ['rgba(0,0,0,0.5)', 'white'],
            extrapolate: 'clamp',
        });

        return (
            <Animated.View
                style={{ flex: 1, backgroundColor: animatedBackgroundColor }}>
                <Animated.View
                    {...this.PanResponder.panHandlers}
                    style={[
                        animatedHeight,
                        {
                            position: 'absolute',
                            left: 0,
                            right: 0,
                            zIndex: 10,
                            backgroundColor: 'white',
                            height: SCREEN_HEIGHT,
                        },
                    ]}>
                    <ScrollView
                        scrollEnabled={this.state.isScrollEnabled}
                        scrollEventThrottle={16}
                        onScroll={event => {
                            this.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={require('../../assets/Logo.png')}
                                    />
                                </Animated.View>
                                <Animated.Text
                                    style={{
                                        opacity: animatedSongTitleOpacity,
                                        fontSize: 18,
                                        paddingLeft: 10,
                                    }}>
                                    Hotel California(Live)
                                </Animated.Text>
                            </View>
                            <Animated.View
                                style={{
                                    opacity: animatedSongTitleOpacity,
                                    flex: 1,
                                    flexDirection: 'row',
                                    justifyContent: 'space-around',
                                }}>
                                <Ionicons name="md-pause" size={32} />
                                <Ionicons name="md-play" size={32} />
                            </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 }}>
                                    Hotel California (Live)
                                </Text>
                                <Text style={{ fontSize: 18, color: '#fa95ed' }}>
                                    Eagles - Hell Freezes Over
                                </Text>
                            </View>

                            <View
                                style={{
                                    height: 40,
                                    width: SCREEN_WIDTH,
                                    alignItems: 'center',
                                }}>
                                <Slider
                                    style={{ width: 300 }}
                                    step={1}
                                    minimumValue={18}
                                    maximumValue={71}
                                    value={18}
                                />
                            </View>

                            <View
                                style={{
                                    flex: 2,
                                    flexDirection: 'row',
                                    alignItems: 'center',
                                    justifyContent: 'space-around',
                                }}>
                                <Ionicons name="md-rewind" size={40} />
                                <Ionicons name="md-pause" size={50} />
                                <Ionicons name="md-fastforward" size={40} />
                            </View>
                            <View
                                style={{
                                    flexDirection: 'row',
                                    justifyContent: 'space-between',
                                    paddingHorizontal: 20,
                                    paddingBottom: 20,
                                }}>
                                <Ionicons
                                    name="md-add"
                                    size={32}
                                    style={{ color: '#fa95ed' }}
                                />
                                <Ionicons
                                    name="md-more"
                                    size={32}
                                    style={{ color: '#fa95ed' }}
                                />
                            </View>
                        </Animated.View>
                        <View style={{ height: 1000 }} />
                    </ScrollView>
                </Animated.View>
            </Animated.View>
        );
    }
}

Bar

Thank you in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.