react-native精美展开菜单

react-native精美展开菜单_第1张图片
代码
拖拽小按钮

import React from "react";
import { Animated, PanResponder } from "react-native";
import { FontAwesome5 } from "@expo/vector-icons";
import styled from "styled-components";


let iconTranslate = new Animated.ValueXY({ x: 0, y: 0 }); // 打开菜单的图标的位移
let prevY = 0;
const DragIcon = ({ setOpenMenu }) => {
  const _panResponder = PanResponder.create({
    onStartShouldSetPanResponder: (evt, gestureState) => true,
    onMoveShouldSetPanResponder: (evt, gestureState) => true,
    onPanResponderGrant: () => {
      console.log('grant')
    },
    onPanResponderMove:(evt, gestureState) => {
      iconTranslate.setValue({
        x:gestureState.dx,
        y:gestureState.dy + prevY
      })
    },
    // onPanResponderMove: Animated.event(
    //   [
    //     null, // 忽略原始事件
    //     { dx: iconTranslate.x },
    //     { dy: iconTranslate.y },
    //   ], // 手势状态参数
    //   { useNativeDriver: false } // 可选的异步监听函数
    // ),
    onPanResponderRelease:(evt, gestureState) => {
      prevY = gestureState.dy;
      Animated.spring(iconTranslate,{
        toValue:{
          x:0,
          y:gestureState.dy
        },
        useNativeDriver: false
      }).start()
    },
  });
  return (
    <AnimatedRadiusBorder
      {..._panResponder.panHandlers}
      style={{
        transform: [
          { translateX: iconTranslate.x },
          { translateY: iconTranslate.y },
        ],
      }}
    >
      <FontAwesome5
        onPress={() => setOpenMenu((x) => true)}
        name="grip-horizontal"
        size={28}
        color="white"
      />
    </AnimatedRadiusBorder>
  );
};

export default DragIcon;

const RadiusBorder = styled.View`
  width: 50px;
  height: 50px;
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
  overflow: hidden;
  position: absolute;
  top: 100px;
  background-color: #51f;
  padding: 10px;
`;
const AnimatedRadiusBorder = Animated.createAnimatedComponent(RadiusBorder);

展开菜单

import React, { useEffect } from "react";
import { Text, Animated, TouchableWithoutFeedback } from "react-native";
import styled from "styled-components";
import { width, height, model } from "../../../constants/Layout";
import { AntDesign } from "@expo/vector-icons";
import { setStatusBarHidden } from "expo-status-bar";
import { Avatar } from 'react-native-paper'

let layout = new Animated.ValueXY({ x: 0, y: 0 });// 整体的宽高
let opacity = new Animated.Value(0);// 整体的透明度
let smallRound = new Animated.Value(height * 0.6);// 小的扇形宽度
let bigRound = new Animated.Value(height * 0.8); // 大的扇形宽度
let RoundHeight = new Animated.Value(height * 0.75);// 两个扇形一致的高度

const AwesomeAnimated = ({ openMenu, setOpenMenu }) => {
  useEffect(() => {
    open(openMenu);
  }, [openMenu]);
  function open(isOpen) {
    if (isOpen) {
      Animated.spring(layout, {
        toValue: { x: height, y: height + 100 },
        useNativeDriver: false,
      }).start();
      Animated.spring(opacity, {
        toValue: 1,
        useNativeDriver: false,
      }).start();
      Animated.timing(smallRound, {
        toValue: height * 0.6,
        duration: 300,
        useNativeDriver: false,
      }).start();
      Animated.timing(bigRound, {
        toValue: height * 0.85,
        duration: 400,
        useNativeDriver: false,
      }).start();
    } else {
      Animated.spring(layout, {
        toValue: { x: 0, y: 0 },
        useNativeDriver: false,
      }).start();
      Animated.spring(opacity, {
        toValue: 0,
        useNativeDriver: false,
      }).start();
      Animated.spring(smallRound, {
        toValue: 0,
        useNativeDriver: false,
      }).start();
      Animated.spring(bigRound, {
        toValue: 0,
        useNativeDriver: false,
      }).start();
    }
    if (model === "ios") {
      setStatusBarHidden(openMenu);
    }
  }
  return (
    <AnimatedContainer
      style={{
        width: layout.y,
        height: layout.y,
        opacity,
      }}
    >
      <AnimatedRoundView
        style={{
          width: bigRound,
          height: RoundHeight,
        }}
      />
      <AnimatedRoundView
        style={{
          width: smallRound,
          height: RoundHeight,
        }}
        bgc="#00009f"
      />
      <ContentContainer>
        <Avatar.Image style={{
          position: 'absolute',
          top: 40,
          right: 30
        }} size={50} source={require('../../../assets/0.jpg')} />
        <Headline>Home</Headline>
        <Headline>My Trips</Headline>
        <Headline>Trip Summary</Headline>
        <Headline>Wallet</Headline>
        <Headline>Setting</Headline>
        <Headline>Feedback</Headline>
        <Headline>Layout</Headline>
        <View>
          <TouchableWithoutFeedback onPress={() => setOpenMenu((x) => false)}>
            <AntDesign
              name="closecircle"
              size={50}
              color="#51f"
            />
          </TouchableWithoutFeedback>
        </View>
      </ContentContainer>
    </AnimatedContainer>
  );
};

export default AwesomeAnimated;

const View = styled.View`
  width: 100%;
  height: 30%;
  position: absolute;
  bottom: 0;
  justify-content: center;
  align-items: center;
`;

const Headline = styled.Text`
  color: #fff;
  padding: 10px;
  font-size: 28px;
  padding-left: 40px;
`;

const RoundView = styled.View`
  background-color: ${(props) => props.bgc || "#04f"};
  border-bottom-right-radius: ${(props) => props.radius || height}px;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
`;
const AnimatedRoundView = Animated.createAnimatedComponent(RoundView);

const ContentContainer = styled.View`
  width: ${width}px;
  height: ${height}px;
  position: absolute;
  top: 0;
  left: 0%;
  z-index: 3;
  padding-top: 20px;
`;

const Container = styled.View`
  position: absolute;
  left: 0px;
  background-color: #42f;
  z-index: 9;
  /* justify-content: center;
  align-items: center; */
  border-bottom-right-radius: ${height}px;
  overflow: hidden;
  background-color: rgba(255, 255, 255, 0.8);
`;

const AnimatedContainer = Animated.createAnimatedComponent(Container);

父容器

import React, { useEffect, useState } from "react";
import { View, Text } from "react-native";
import AwesomeAnimatedMenu from "./components/AwesomeAnimatedMenu";
import DragIcon from './components/DragIcon'

const UITest = (props) => {
  const [openMenu, setOpenMenu] = useState(false);
  useEffect(() => {
    
  },[]);
  
  return (
    <View
      style={{
        position: "relative",
      }}
    >
      <DragIcon setOpenMenu={setOpenMenu} />
      <AwesomeAnimatedMenu openMenu={openMenu} setOpenMenu={setOpenMenu} />
    </View>
  );
};

export default UITest;


你可能感兴趣的:(react-native)