水平滚动视图捕捉反应本机

Horizontal scrollview snapping react native

您好,我正在尝试实现 scrollview 居中对齐 如下所示 gif link

Check This Gif

但是做不到。以下是实现此目的的本机反应代码。

或者是否有任何方法可以滚动到滚动视图元素的特定索引,例如 android?

如有任何帮助,我们将不胜感激。 提前致谢

<ScrollView
  style={[styles.imgContainer,{backgroundColor:colorBg,paddingLeft:20}]}
  automaticallyAdjustInsets={false}
  horizontal={true}
  pagingEnabled={true}
  scrollEnabled={true}
  decelerationRate={0}
  snapToAlignment='center'
  snapToInterval={DEVICE_WIDTH-100}
  scrollEventThrottle={16}
  onScroll={(event) => {
    var contentOffsetX=event.nativeEvent.contentOffset.x;
    var contentOffsetY=event.nativeEvent.contentOffset.y;

    var  cellWidth = (DEVICE_WIDTH-100).toFixed(2);
    var cellHeight=(DEVICE_HEIGHT-200).toFixed(2);

    var  cellIndex = Math.floor(contentOffsetX/ cellWidth);

    // Round to the next cell if the scrolling will stop over halfway to the next cell.
    if ((contentOffsetX- (Math.floor(contentOffsetX / cellWidth) * cellWidth)) > cellWidth) {
      cellIndex++;
    }

    // Adjust stopping point to exact beginning of cell.
    contentOffsetX = cellIndex * cellWidth;
    contentOffsetY= cellIndex * cellHeight;

    event.nativeEvent.contentOffsetX=contentOffsetX;
    event.nativeEvent.contentOffsetY=contentOffsetY;

    // this.setState({contentOffsetX:contentOffsetX,contentOffsetY:contentOffsetY});
    console.log('cellIndex:'+cellIndex);

    console.log("contentOffsetX:"+contentOffsetX);
      // contentOffset={{x:this.state.contentOffsetX,y:0}}
  }}
>
  {rows}

</ScrollView>

有几个选项。这里有两个我已经尝试过并且工作正常。我更喜欢第二个,因为正如它的文档所说 "like ListView, this can render hundreds of pages without performance issue".

  1. react-native-page-swiper
  2. react-native-viewpager

您不需要其他库,您可以使用 ScrollView 做到这一点。您只需要在您的组件中添加以下道具。

    horizontal= {true}
    decelerationRate={0}
    snapToInterval={200} //your element width
    snapToAlignment={"center"}

查看此快餐以了解有关如何实施它的更多详细信息 https://snack.expo.io/H1CnjIeDb

ScrollView中使用pagingEnabled属性。

const screenHeight = Dimensions.get('window').height;

class Screen extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <ScrollView pagingEnabled>
        <Page1 style={{height: screenHeight}} />
        <Page2 style={{height: screenHeight}} />
      </ScrollView>
    );
  }
}

如果您不想使用 snapToInterval 因为长列表未对齐,您可以使用更精确的 snapToOffsets。

例如:

const { width } = Dimensions.get('window');
this.IMAGE_WIDTH = width * (1 / 2.5)
this.image_margin = 5
this.nishhar = width - ((this.IMAGE_WIDTH + this.image_margin) * 2 + this.image_margin * 2)

dataNum = [1, 2, 3, 4, 5, 6]

return (<FlatList
            data={dataNum}
            renderItem={item => {
                return (
                    <View style={{
                        backgroundColor: item.index % 2 == 0 ? 'red' : 'blue',
                        width: this.IMAGE_WIDTH,
                        height: this.IMAGE_WIDTH,
                        marginLeft: this.image_margin,
                        marginRight: this.image_margin,
                    }}>
                    </View>)
            }}
            keyExtractor={this.keyGenerator}
            horizontal={true}
            snapToAlignment={"start"}
            snapToOffsets={[...Array(dataNum.length)].map((x, i) => (i * (this.IMAGE_WIDTH + 2 * this.image_margin) - (this.nishhar * 0.5)))}
            decelerationRate={"fast"}
            pagingEnabled
        />)

或者您也可以查看此示例: https://snack.expo.io/SyWXFqDAB

我在 iOS 上遇到了 FlatList 的 snapToInterval 逻辑问题(在水平列表上它并不总是正确地捕捉到 start) - 我通过增加以下属性的值来解决这个问题(我有单项滑块)

maxToRenderPerBatch={6}
initialNumToRender={6}
windowSize={6}

尝试使用 snapToOffsets 道具。不过这需要简单的加法和乘法。

要创建显示 2 个元素的对齐效果,以及与超出边界的左右元素 10pts;

// import useWindowDimensions from 'react-native'
const { width: windowWidth } = useWindowDimensions();

// the width of a card in ScrollView
// 20 is so out of bound cards on left & right can have 10pts visible;
const cardWidth = (windowWidth / 2) - 20;

// gap between each cards;
const gap = 16;

const halfGap = gap / 2;

const cardContent = [1, 2, 3, 4, 5]

// THIS IS THE FUN PART
const snapOffsets = cardContent
      .map((_, index) => {            
        return (cardWidth * index) + (halfGap * index)
      })

// add left and right margin to <Card/> for gap effect,
// as well as width using cardWidth above 
// conditional left margin to first card, and right margin to last card

return (
   <ScrollView
     horizontal={true}
     snapToOffsets={snapOffsets}
   >
     { 
       cardContent.map((item, index, arr) => {
         return (
           <Card 
             key={index} 
             title={item} 
             style={{
               width: cardWidth,
               marginLeft: index == 0 ? gap : 0,
               marginRight: index == arr.length - 1 ? gap : halfGap
             }}
           />
         )
       })
     }
   </ScrollView>
)

就是这样。您可以重构垂直模式。

For a better edge to edge effect, make sure that ancestor containers don't have padding