欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

react-native精美展开菜单

程序员文章站 2022-04-19 10:28:55
代码拖拽小按钮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 }); // 打开菜单的图标的位移....

react-native精美展开菜单
代码
拖拽小按钮

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;


本文地址:https://blog.csdn.net/printf_hello/article/details/107201865