【问题标题】:Increase height of a View on swipe up in react native expo在反应原生博览会中向上滑动时增加视图的高度
【发布时间】:2022-09-24 02:07:09
【问题描述】:

我有一个包含多个视图的容器,如下所示:

export default function MyComponent() {

<View *** container *** >
<View> // some stuff </View>
<View> // some stuff </View>
<ScrollView> // some stuff </ScrollView>
</View
}

ScrollView 大约是容器高度的 40%,处于绝对位置。

我需要做的是能够通过向上滑动将其扩展到整个屏幕。

我尝试使用一些模态 npm 包,但无法使其工作。

  • 当您说向上滑动时,您是指在屏幕上的任意位置滑动还是仅在滚动视图中滚动?

标签: react-native gesture


【解决方案1】:

一些东西:

  • 根据我的经验,ScrollViews 和FlatLists 在它们的 flex 为 1 并且包装在限制其大小的父容器中时效果最佳。
  • 我无法确定您是想将整个屏幕包裹在 GestureDector 中并收听滑动,还是只希望 ScrollView 收听滚动事件。因为您希望 ScrollView 占据整个屏幕,所以我假设您想收听 onScroll 事件

所以这是我整理的demo

import * as React from 'react';
import { 
  Text,
  View,
  Animated,
  StyleSheet,
  ScrollView,
  useWindowDimensions
  } from 'react-native';
import Constants from 'expo-constants';
import Box from './components/Box';
import randomColors from './components/colors'
const throttleTime = 200;

// min time between scroll events (in milliseconds)
const scrollEventThrottle = 100;
// min up/down scroll distance to trigger animatino
const scrollYThrottle = 2;

export default function App() {
  const scrollViewAnim = React.useRef(new Animated.Value(0)).current;
  let lastY = React.useRef(0).current;
  // used to throttle scroll events
  let lastScrollEvent = React.useRef(Date.now()).current;
  const [{ width, height }, setViewDimensions] = React.useState({});
  const [isScrollingDown, setIsScrollingDown] = React.useState(false);
  const [scrollViewTop, setScrollViewTop] = React.useState(400);
  // scroll view is 40% of view height
  const defaultHeight = height * .4;
  // call onLayout on View before scrollView
  const onLastViewLayout = ({nativeEvent})=>{
    // combine the y position with the layout height to
    // determine where to place scroll view
    setScrollViewTop(nativeEvent.layout.y + nativeEvent.layout.height)
  }
  const onContainerLayout = ({nativeEvent})=>{
    // get width and height of parent container
    // using this instead of useWindowDimensions allow
    // makes the scrollView scale with parentContainer size 
    setViewDimensions({
      width:nativeEvent.layout.width,
      height:nativeEvent.layout.height
    })
  }
  //animation style
  let animatedStyle = [styles.scrollView,{
    height:scrollViewAnim.interpolate({
      inputRange:[0,1],
      outputRange:[defaultHeight,height]
    }),
    width:width,
    top:scrollViewAnim.interpolate({
      inputRange:[0,1],
      outputRange:[scrollViewTop,-10]
    }),
    bottom:60,
    left:0,
    right:0
  }]
  const expandScrollView = ()=>{
    Animated.timing(scrollViewAnim,{
      toValue:1,
      duration:200,
      useNativeDriver:false
    }).start()
  }
  const shrinkScrollView = ()=>{
    Animated.timing(scrollViewAnim,{
      toValue:0,
      duration:200,
      useNativeDriver:false
    }).start()
  }
  const onScroll=(e)=>{
    // throttling by time between scroll activations
    if(Date.now() - lastScrollEvent <scrollEventThrottle ){
      console.log('throttling!')
      return
    }
    lastScrollEvent = Date.now()
    // destructure event object
    const {nativeEvent:{contentOffset:{x,y}}} = e;
    const isAtTop = y <= 0
    const isPullingTop = lastY <= 0 && y <= 0
    let yDiff = y - lastY
    let hasMajorDiff = Math.abs(yDiff) > scrollYThrottle
    // throttle if isnt pulling top and scroll dist is small
    if(!hasMajorDiff && !isPullingTop  ){
      return
    }
    const hasScrolledDown = yDiff > 0
    const hasScrolledUp = yDiff < 0
    if(hasScrolledDown){
      setIsScrollingDown(true);
      expandScrollView()
    }
    if(isAtTop || isPullingTop){
      setIsScrollingDown(false)
      shrinkScrollView();
    }
    lastY = y
  }
  return (
    <View style={styles.container} onLayout={onContainerLayout}>
      <Box color={randomColors[0]} text="Some text"/>
      <Box color={ randomColors[1]} text="Some  other text "/>
      <View style={styles.lastView} 
        onLayout={onLastViewLayout}>
        <Text>ScrollView Below </Text>
      </View>
      <Animated.View style={animatedStyle}>
        <ScrollView
          onScroll={onScroll}
          style={{flex:1}}
        >
          {randomColors.map((color,i)=>
            <Box color={color} height={60} text={"Item Number "+(i+1)}/>
          )}
        </ScrollView>
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    // justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    padding: 8,
  },
  scrollView:{
    // position:'absolute',
    position:'absolute',
    marginVertical:10,
    height:'40%',
    backgroundColor:'lightgray'
  },
  lastView:{
    alignItems:'center',
    paddingVertical:5,
    borderBottomWidth:1,
    borderTopWidth:1
  }
});

结果是向下滚动时,scrollview 会展开并占据整个屏幕,而当用户滚动到顶部时会缩小。

编辑:我发现直接在滚动视图之前获取视图的 y 位置和高度可以很容易地计算出 ScrollView 的位置,从而使 ScrollView 始终处于绝对位置。

【讨论】:

    【解决方案2】:

    这是一个非常基本的示例,说明如何使用 FlatList(类似于 ScrollView)并允许您想要的滚动行为:

    import React from "react";
    import {Text,View} from "react-native";
    
    const App = () => {
    
      const myData = {//everything you want rendered in flatlist}
    
      const renderSomeStuff = () => {
          return (
             <View>
               <Text> Some Stuff </Text>
             </View>
        )
      };
    
      const renderOtherStuff = () => {
          return (
            <View>
              <Text> Other Stuff </Text>
            </View>
          );
      };
    
    
      return (
        <View>
          <FlatList
            data={myData}
            keyExtractor={(item) => `${item.id}`}
            showsVerticalScrollIndicator
            ListHeaderComponent={
              <View>
                {renderSomeStuff()}
                {renderOtherStuff()}
              </View>
            }
            renderItem={({ item }) => (
                <View>
                  <Text>{item}</Text>
                </View>
            )}
            ListFooterComponent={
              <View></View>
            }
          />
        </View>
      );
    };
    
    export default App;
    

    【讨论】:

      猜你喜欢
      • 2018-08-19
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多