redux 如何< View/>在React Native中从底部滑进滑出?

8yoxcaq7  于 2023-03-02  发布在  React
关注(0)|答案(5)|浏览(165)

在React Native iOS中,我想在下图中滑入和滑出一个like。
在下面的示例中,当按下按钮时,Payment Information视图从底部弹出,当按下折叠按钮时,它返回并消失。
这样做的正确和适当的方法是什么?

先谢谢你!

编辑

58wvjzkj

58wvjzkj1#

基本上,你需要把你的视图绝对定位到屏幕的底部,然后你平移它的y值使其等于它的高度。(子视图必须有一个特定的高度,以便知道它移动了多少)
代码:

'use strict';

import React, {Component} from 'react';
import ReactNative from 'react-native';

const {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  Animated
} = ReactNative;

var isHidden = true;

class AppContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      bounceValue: new Animated.Value(100),  //This is the initial position of the subview
      buttonText: "Show Subview"
    };
  }
  
  
  _toggleSubview() {    
    this.setState({
      buttonText: !isHidden ? "Show Subview" : "Hide Subview"
    });
    
    var toValue = 100;
    
    if(isHidden) {
      toValue = 0;
    }

    //This will animate the transalteY of the subview between 0 & 100 depending on its current state
    //100 comes from the style below, which is the height of the subview.
    Animated.spring(
      this.state.bounceValue,
      {
        toValue: toValue,
        velocity: 3,
        tension: 2,
        friction: 8,
      }
    ).start();
    
    isHidden = !isHidden;
  }
  
  render() {
    return (
      <View style={styles.container}>
          <TouchableHighlight style={styles.button} onPress={()=> {this._toggleSubview()}}>
            <Text style={styles.buttonText}>{this.state.buttonText}</Text>
          </TouchableHighlight>
          <Animated.View
            style={[styles.subView,
              {transform: [{translateY: this.state.bounceValue}]}]}
          >
            <Text>This is a sub view</Text>
          </Animated.View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    marginTop: 66
  },
  button: {
    padding: 8,
  },
  buttonText: {
    fontSize: 17,
    color: "#007AFF"
  },
  subView: {
    position: "absolute",
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: "#FFFFFF",
    height: 100,
  }
});

AppRegistry.registerComponent('AppContainer', () => AppContainer);
ltskdhd1

ltskdhd12#

我知道这有点晚了,但是我想它可能对某些人有用。你应该试试一个叫做rn-sliding-out-panel的组件。它工作得非常好。https://github.com/octopitus/rn-sliding-up-panel

<SlidingUpPanel
    draggableRange={top: 1000, bottom: 0}
    showBackdrop={true|false /*For making it modal-like*/}
    ref={c => this._panel = c}
    visible={ture|false /*If you want it to be visible on load*/}
></SlidingUpPanel>

您甚至可以通过外部按钮打开它:

<Button onPress={()=>{this._panel.transitionTo(1000)}} title='Expand'></Button>

您可以通过npm安装它:sudo npm install rn-sliding-out-panel --save位于您的react-native根目录上。
我希望它能对某人有所帮助:D

t1qtbnec

t1qtbnec3#

我创建了一个可重用的BottomSheet组件,它接受任何内容。
它看起来是这样的:

下面是BottomSheet组件的代码(TypeScript格式):

import * as React from 'react'
import {
  Animated,
  Easing,
  Pressable,
  StyleSheet,
  useWindowDimensions,
  View,
} from 'react-native'

const DEFAULT_HEIGHT = 300

function useAnimatedBottom(show: boolean, height: number = DEFAULT_HEIGHT) {
  const animatedValue = React.useRef(new Animated.Value(0))

  const bottom = animatedValue.current.interpolate({
    inputRange: [0, 1],
    outputRange: [-height, 0],
  })

  React.useEffect(() => {
    if (show) {
      Animated.timing(animatedValue.current, {
        toValue: 1,
        duration: 350,
        // Accelerate then decelerate - https://cubic-bezier.com/#.28,0,.63,1
        easing: Easing.bezier(0.28, 0, 0.63, 1),
        useNativeDriver: false, // 'bottom' is not supported by native animated module
      }).start()
    } else {
      Animated.timing(animatedValue.current, {
        toValue: 0,
        duration: 250,
        // Accelerate - https://easings.net/#easeInCubic
        easing: Easing.cubic,
        useNativeDriver: false,
      }).start()
    }
  }, [show])

  return bottom
}

interface Props {
  children: React.ReactNode
  show: boolean
  height?: number
  onOuterClick?: () => void
}

export function BottomSheet({
  children,
  show,
  height = DEFAULT_HEIGHT,
  onOuterClick,
}: Props) {
  const { height: screenHeight } = useWindowDimensions()

  const bottom = useAnimatedBottom(show, height)

  return (
    <>
      {/* Outer semitransparent overlay - remove it if you don't want it */}
      {show && (
        <Pressable
          onPress={onOuterClick}
          style={[styles.outerOverlay, { height: screenHeight }]}
        >
          <View />
        </Pressable>
      )}
      <Animated.View style={[styles.bottomSheet, { height, bottom }]}>
        {children}
      </Animated.View>
    </>
  )
}

const styles = StyleSheet.create({
  outerOverlay: {
    position: 'absolute',
    width: '100%',
    zIndex: 1,
    backgroundColor: 'black',
    opacity: 0.3,
  },
  bottomSheet: {
    position: 'absolute',
    width: '100%',
    zIndex: 1,
    // Here you can set a common style for all bottom sheets, or nothing if you
    // want different designs
    backgroundColor: 'dodgerblue',
    borderRadius: 16,
  },
})

我把这段代码放在一个名为BottomSheet.tsx的文件中。
BottomSheet的使用方法如下:

import * as React from 'react'
import {
  Pressable,
  SafeAreaView,
  StatusBar,
  StyleSheet,
  Text,
  View,
} from 'react-native'
import { BottomSheet } from './src/BottomSheet'

const App = () => {
  const [showBottomSheet, setShowBottomSheet] = React.useState(false)

  const hide = () => {
    setShowBottomSheet(false)
  }

  return (
    <SafeAreaView style={styles.safeAreaView}>
      <StatusBar barStyle={'dark-content'} />
      <View style={styles.container}>
        <Pressable
          onPress={() => {
            setShowBottomSheet(true)
          }}
          style={styles.showButton}
        >
          <Text style={styles.buttonText}>Show bottom sheet</Text>
        </Pressable>
      </View>

      <BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}>
        <View style={styles.bottomSheetContent}>
          <Text style={styles.bottomSheetText}>Hey boys, hey girls!</Text>
          <Pressable onPress={hide} style={styles.bottomSheetCloseButton}>
            <Text style={styles.buttonText}>X Close</Text>
          </Pressable>
        </View>
      </BottomSheet>
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  safeAreaView: {
    flex: 1,
  },
  container: {
    flex: 1,
  },
  showButton: {
    marginTop: 48,
    padding: 16,
    backgroundColor: 'mediumspringgreen',
    alignSelf: 'center',
    borderRadius: 8,
  },
  buttonText: {
    fontSize: 20,
  },
  bottomSheetContent: {
    padding: 40,
    alignItems: 'center',
  },
  bottomSheetText: {
    fontSize: 24,
    marginBottom: 80,
  },
  bottomSheetCloseButton: {
    padding: 16,
    backgroundColor: 'deeppink',
    borderRadius: 8,
  },
})

export default App

注:

  • 我已经把外部半透明覆盖,但你可以摆脱它删除。
  • 我选择了在你点击外部半透明覆盖层时关闭模态函数,这是通过onOuterClick回调函数实现的,这是可选的--如果你不想做任何事情,就不要传递它。
  • 我已经把一些样式(蓝色背景+边界半径),适用于所有的底部床单,但你可以删除它,如果你想有不同的风格。
7vux5j2d

7vux5j2d4#

经过长时间的搜索,我找到了一个非常好的库,叫做react-native-swipe-down,有MIT许可证。它可以帮助你毫不费力地制作一个滑块<View />
我希望这个图书馆能帮到你。

import SwipeUpDown from 'react-native-swipe-up-down';

<SwipeUpDown        
    itemMini={<ItemMini />} // Pass props component when collapsed
    itemFull={<ItemFull />} // Pass props component when show full
    onShowMini={() => console.log('mini')}
    onShowFull={() => console.log('full')}
    onMoveDown={() => console.log('down')}
    onMoveUp={() => console.log('up')}
    disablePressToShow={false} // Press item mini to show full
    style={{ backgroundColor: 'green' }} // style for swipe
/>
knpiaxh1

knpiaxh15#

为了达到上述要求,我们可以借助一些大的图书馆
1.@gorhom/底层床单

  1. react-native-raw-bottom-sheet
    但是如果我们想原生地完成它,请找到下面显示的代码,我将尝试证明答案:)
    对于一些动画效果,我将从打击地点how-to-create-moving-animations-in-react-native获取参考
import React, { useState } from 'react'
import { SafeAreaView, View, ScrollView, Text, Dimensions, TouchableOpacity, Animated } from 'react-native'

const App = () => {

    const { height, width } = Dimensions.get('window')
    const SCREEN_HEIGHT = Math.round(height)
    const SCREEN_WIDTH = Math.round(width)
    // Animation
    const startValue = new Animated.Value(Math.round(height + height * 0.3))
    const endValue = Math.round(height - height * 0.3)
    const duration = 1000

    const _showBottomView = (key) => {

        const toValue = key === 'HIDE' ? height : endValue

        Animated.timing(startValue, {
            toValue,
            duration: duration,
            useNativeDriver: true,
        }).start()

    }

    return (
        <SafeAreaView style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.1)' }}>

            {/* Header */}
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'black', margin: 5 }}>
                <Text>
                    Header
                </Text>
            </View>

            <View style={{ flex: 9, borderWidth: 1, borderColor: 'black', margin: 5 }}>
                <ScrollView
                    style={{ flex: 1 }}>

                    {/* Title View */}
                    <View style={{ height: SCREEN_HEIGHT * 0.1, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
                        <Text>
                            Content ONE
                        </Text>
                    </View>

                    <View style={{ height: SCREEN_HEIGHT * 0.5, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
                        <Text>
                            Content TWO
                        </Text>

                    </View>

                    <View style={{ height: SCREEN_HEIGHT * 0.2, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
                        <TouchableOpacity
                            activeOpacity={0.85}
                            onPress={() => _showBottomView()}
                            style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
                            <Text>
                                SHOW BOTTOM VIEW
                            </Text>
                        </TouchableOpacity>
                    </View>

                    <View style={{ height: SCREEN_HEIGHT * 0.3, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', marginBottom: SCREEN_HEIGHT * 0.01 }}>
                        <Text>
                            ...REST_CONTENT...
                        </Text>
                    </View>
                </ScrollView>
            </View>

            {/* Bottom view */}

            <Animated.View
                style={[
                    {
                        position: 'absolute',
                        height: height * 0.3,
                        width: width,
                        backgroundColor: 'white',
                        alignItems: 'center', justifyContent: 'center',
                        borderTopRightRadius: 23, borderTopLeftRadius: 23,
                        transform: [
                            {
                                translateY: startValue
                            },
                        ],
                    },
                ]} >

                <TouchableOpacity
                    activeOpacity={0.85}
                    onPress={() => _showBottomView('HIDE')}
                    style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
                    <Text>
                        HIDE BOTTOM VIEW
                    </Text>
                </TouchableOpacity>

            </Animated.View>

        </SafeAreaView>
    )
}

export default App

演示

相关问题