首页 > 解决方案 > React Native 椭圆滚动

问题描述

我怎样才能做一个类似的椭圆形滚动

我可以为此使用什么?

在此处输入图像描述

标签: react-nativescrollscrollviewflatlist

解决方案


基于你想要这样的假设我写了一个简单的例子

如果有一天链接被破坏,下面我另外附上代码

import React, { useCallback, useState, useRef } from "react";
import {
  FlatList,
  Text,
  View,
  StyleSheet,
  Dimensions,
  Animated
} from "react-native";

const { height } = Dimensions.get("window");
const screenMiddle = height / 2;
const itemScaleOffset = height / 3;

const DATA = new Array(20).fill(0).map((...args) => ({
  id: args[1],
  title: args[1]
}));
// args[1] is an index, just I hate warnings

const Item = ({ title, offsetY }) => {
  const [scrollEdges, setScrollEdges] = useState({
    top: 0,
    middle: 0,
    bottom: 0
  });

  const onLayout = useCallback(
    ({
      nativeEvent: {
        layout: { top, height }
      }
    }) =>
      setScrollEdges((edges) => ({
        ...edges,
        top: top - itemScaleOffset - screenMiddle,
        middle: top + height / 2 - screenMiddle,
        bottom: top + height + itemScaleOffset - screenMiddle
      })),
    []
  );

  const scale = offsetY.interpolate({
    inputRange: [scrollEdges.top, scrollEdges.middle, scrollEdges.bottom],
    outputRange: [0.66, 1, 0.66],
    extrapolate: "clamp"
  });

  return (
    <Animated.View
      onLayout={onLayout}
      style={[
        {
          transform: [
            {
              scale
            }
          ]
        },
        styles.item
      ]}
    >
      <Text style={styles.title}>{title}</Text>
    </Animated.View>
  );
};

const keyExtractor = ({ id }) => id.toString();

const App = () => {
  const offsetY = useRef(new Animated.Value(0)).current;

  const renderItem = useCallback(
    ({ item: { title } }) => <Item title={title} offsetY={offsetY} />,
    [offsetY]
  );

  return (
    <View style={styles.app}>
      <FlatList
        data={DATA}
        renderItem={renderItem}
        keyExtractor={keyExtractor}
        onScroll={Animated.event(
          [
            {
              nativeEvent: {
                contentOffset: {
                  y: offsetY
                }
              }
            }
          ],
          {
            useNativeDriver: false
          }
        )}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  app: {
    flex: 1
  },
  item: {
    backgroundColor: "#f9c2ff",
    padding: 20,
    marginVertical: 8,
    marginHorizontal: 16
  },
  title: {
    fontSize: 32
  }
});

export default App;

推荐阅读