【问题标题】:How do I center an item within a React Native ListView?如何在 React Native ListView 中将项目居中?
【发布时间】:2017-04-20 04:10:54
【问题描述】:

我正在尝试在选择时将一个项目中心居中。我目前的策略是首先测量项目并滚动到视图中引用项目的 x 坐标。

目前,任何时候我按下一个项目 ListView 都会滚动到最后 x: 538

有没有更简单的方法来实现这一点,同时保持代码无状态/功能?

const ItemScroll = (props) => {

  const createItem = (obj, rowID) => {

    const isCurrentlySelected = obj.id === props.currentSelectedID

    function scrollToItem(_scrollViewItem, _scrollView) {
      // measures the item coordinates
      _scrollViewItem.measure((fx) => {
        console.log('measured fx: ', fx)
        const itemFX = fx;
        // scrolls to coordinates
        return _scrollView.scrollTo({ x: itemFX });
      });
    }
    return (
      <TouchableHighlight
        ref={(scrollViewItem) => { _scrollViewItem = scrollViewItem; }}
        isCurrentlySelected={isCurrentlySelected}
        style={isCurrentlySelected ? styles.selectedItemContainerStyle : styles.itemContainerStyle}
        key={rowID}
        onPress={() => { scrollToItem( _scrollViewItem, _scrollView); props.onEventFilterPress(obj.id, rowID) }}>
        <Text style={isCurrentlySelected ? styles.selectedItemStyle : styles.itemStyle} >
          {obj.title}
        </Text>
      </TouchableHighlight>
    )
  };
  return (
    <View>
      <ScrollView
        ref={(scrollView) => { _scrollView = scrollView; }}
        horizontal>
        {props.itemList.map(createItem)}
        {props.onItemPress}
      </ScrollView>
    </View>
  );
};

更新

有了@Ludovic 的建议,我现在切换到 FlatList,我不确定如何使用功能组件触发 scrollToIndex。下面是我的新ItemScroll

const ItemScroll = (props) => {

  const {
      itemList,
      currentSelectedItem
      onItemPress } = props

  const renderItem = ({item, data}) => {
    const isCurrentlySelected = item.id === currentSelectedItem

    const _scrollToIndex = () => { return { viewPosition: 0.5, index: data.indexOf({item}) } }

    return (
      <TouchableHighlight
        // Below is where i need to run onItemPress in the parent
        // and scrollToIndex in this child.
        onPress={[() => onItemFilterPress(item.id), scrollToIndex(_scrollToIndex)]} >
        <Text style={isCurrentlySelected ? { color: 'red' } : { color: 'blue' }} >
          {item.title}
        </Text>
      </TouchableHighlight>
    )
  }
  return (
    <FlatList
      showsHorizontalScrollIndicator={false}
      data={itemList}
      keyExtractor={(item) => item.id}
      getItemLayout={(data, index) => (
          // Max 5 items visibles at once
          { length: Dimensions.get('window').width / 5, offset: Dimensions.get('window').width / 5 * index, index }
      )}
      horizontal        
      // Here is the magic : snap to the center of an item
      snapToAlignment={'center'} 
      // Defines here the interval between to item (basically the width of an item with margins)
      snapToInterval={Dimensions.get('window').width / 5}
      renderItem={({item, data}) => renderItem({item, data})} />
  );
};

【问题讨论】:

    标签: javascript listview react-native functional-programming


    【解决方案1】:

    在我看来,你应该使用FlatList

    FlatList 有一个方法scrollToIndex 允许直接转到您的数据项。它与 ScrollView 几乎相同,但更智能。遗憾的是文档很差。

    这是我做的一个 FlatList 的例子

    let datas = [{key: 0, text: "Hello"}, key: 1, text: "World"}]
    
    <FlatList
        // Do something when animation ended
        onMomentumScrollEnd={(e) => this.onScrollEnd(e)} 
        ref="flatlist"
        showsHorizontalScrollIndicator={false}
        data={this.state.datas}
        keyExtractor={(item) => item.key}
        getItemLayout={(data, index) => (
            // Max 5 items visibles at once
            {length: Dimensions.get('window').width / 5, offset: Dimensions.get('window').width / 5 * index, index}   
        )}
        horizontal={true}
        // Here is the magic : snap to the center of an item
        snapToAlignment={'center'}  
        // Defines here the interval between to item (basically the width of an item with margins)
        snapToInterval={Dimensions.get('window').width / 5}    
        style={styles.scroll}
        renderItem={ ({item}) =>
            <TouchableOpacity
                onPress={() => this.scrollToIndex(/* scroll to that item */)}
                style={styles.cell}>
                <Text>{item.text}</Text>
            </TouchableOpacity>
        }
    />
    

    更多关于 FlatList 的信息:https://facebook.github.io/react-native/docs/flatlist#__docusaurus

    【讨论】:

    • 如何为scrollToIndex 指定索引?它是键、可见项数组中的索引,还是整个数组中的索引?
    • 数组中的索引
    • onPress={() =&gt; scrollToIndex({viewPosition: 0.5, index: data.indexOf({item})})} 会是一个解决方案吗?
    • 是的,你的情况可能更好!但是滚动到应该发生一个动作。
    • 我的 FlatList 可以工作,但不能滚动 onPress,因为我使用的是无法使用 this.scrollToIndex 的功能组件。我还需要在onPress 中将函数传递给父级。你对如何实现scrollToIndex有什么建议吗?
    【解决方案2】:

    viewPosition 道具将使您的项目居中。

    flatListRef.scrollToIndex({ index: index, animated: true, viewPosition: 0.5 })
    

    【讨论】:

      【解决方案3】:
      flatlistRef.current.scrollToIndex({
                          animated: true,
                          index,
                          viewOffset: Dimensions.get('window').width / 2.5,
                        });
      

      您可以尝试将 viewOffset 放在 scrollToIndex 属性中,它将处理您的组件偏移量,我使用 2.5 使其位于屏幕中间,因为我每个部分显示 5 个项目,其中一个焦点项目将位于屏幕中间

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-25
        • 2018-01-06
        • 2016-05-23
        • 1970-01-01
        • 1970-01-01
        • 2015-12-31
        • 2017-03-19
        • 1970-01-01
        相关资源
        最近更新 更多