使用ListView如何知道第header部分在最上面?

How to know which section header is on the top when use ListView?

我想获取每个部分 header 位于顶部时的 y 位置值。

比如A、B、C是我的header标题,当A在最上面时y值是100,B是500,C是1200.

我的react native项目版本是0.44.2,所以我用ListView实现SectionList

这是我的 ListView 来自 FaceBook 源代码的代码:

'use strict';

var ListView = require('ListView');
var Dimensions = require('Dimensions');
var Platform = require('Platform');
var StyleSheet = require('StyleSheet');
var React = require('React');
var View = require('View');

type Rows = Array<Object>;
type RowsAndSections = {
  [sectionID: string]: Object;
};

export type Data = Rows | RowsAndSections;
type RenderElement = () => ?ReactElement;

type Props = {
  data: Data;
  renderEmptyList?: ?RenderElement;
  minContentHeight: number;
  contentInset: { top: number; bottom: number; };
  contentOffset: { x: number; y: number; };
};

type State = {
  contentHeight: number;
  dataSource: ListView.DataSource;
};

// FIXME: Android has a bug when scrolling ListView the view insertions
// will make it go reverse. Temporary fix - pre-render more rows
const LIST_VIEW_PAGE_SIZE = Platform.OS === 'android' ? 20 : 1;

class PureListView extends React.Component {
  props: Props;
  state: State;

  static defaultProps = {
    data: [],
    contentInset: { top: 0, bottom: 0 },
    contentOffset: { x: 0, y: 0 },
    // TODO: This has to be scrollview height + fake header
    minContentHeight: 0, //Dimensions.get('window').height,
    // renderSeparator: (sectionID, rowID) => <View style={styles.separator} key={rowID} />,
  };

  constructor(props: Props) {
    super(props);
    let dataSource = new ListView.DataSource({
      getRowData: (dataBlob, sid, rid) => dataBlob[sid][rid],
      getSectionHeaderData: (dataBlob, sid) => dataBlob[sid],
      rowHasChanged: (row1, row2) => row1 !== row2,
      sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
    });

    this.state = {
      contentHeight: 0,
      dataSource: cloneWithData(dataSource, props.data),
    };

    (this: any).renderFooter = this.renderFooter.bind(this);
    (this: any).onContentSizeChange = this.onContentSizeChange.bind(this);
  }

  componentWillReceiveProps(nextProps: Props) {
    if (this.props.data !== nextProps.data) {
      this.setState({
        dataSource: cloneWithData(this.state.dataSource, nextProps.data),
      });
    }
  }

  render() {
    const {contentInset} = this.props;
    const {contentOffset} = this.props;
    // console.log('ESDebug:content offset');
    // console.log(contentOffset);
    const bottom = contentInset.bottom +
      Math.max(0, this.props.minContentHeight - this.state.contentHeight);
    var removeSubviews = false;
    if (Platform.OS === 'android') {
      removeSubviews = true;
    }
    return (
      <ListView
        initialListSize={5}
        pageSize={LIST_VIEW_PAGE_SIZE}
        {...this.props}
        ref="listview"
        dataSource={this.state.dataSource}
        renderFooter={this.renderFooter}
        contentInset={{bottom, top: contentInset.top}}
        contentOffset={contentOffset}
        onContentSizeChange={this.onContentSizeChange}
        scrollEventThrottle={1000}
        decelerationRate ={'normal'}
        removeClippedSubviews={true}
      />
    );
  }

  onContentSizeChange(contentWidth: number, contentHeight: number) {
    if (contentHeight !== this.state.contentHeight) {
      this.setState({contentHeight});
    }
  }

  scrollTo(...args: Array<any>) {
    this.refs.listview.scrollTo(...args);
  }

  getScrollResponder(): any {
    return this.refs.listview.getScrollResponder();
  }

  renderFooter(): ?ReactElement {
    if (this.state.dataSource.getRowCount() === 0) {
      return this.props.renderEmptyList && this.props.renderEmptyList();
    }

    return this.props.renderFooter && this.props.renderFooter();
  }
}

function cloneWithData(dataSource: ListView.DataSource, data: ?Data) {
  if (!data) {
    return dataSource.cloneWithRows([]);
  }
  if (Array.isArray(data)) {
    return dataSource.cloneWithRows(data);
  }
  return dataSource.cloneWithRowsAndSections(data);
}

var styles = StyleSheet.create({
  separator: {
    backgroundColor: '#eeeeee',
    height: 1,
  },
});

module.exports = PureListView;

这是我关于 ListView:

的组件代码
    var PureListView = require('../../common/PureListView');

    render() {
      return (
             <PureListView
                ref={(pureListView) => { this.pureListView = pureListView; }}
                style = {{marginTop:0, backgroundColor:'white'}}
                contentContainerStyle = {{flexDirection: 'row',flexWrap: 'wrap'}}
                data= {this.state.sectionData}
                renderEmptyList={this.renderEmptyList}
                renderSectionHeader={this._renderSectionHeader}
                onScroll={this._onScroll}
                renderRow={this._renderRow}
                navigator={this.props.navigator}
              />
      );
    }

我从_onScroll函数中得到y位置值,但是我不知道当A或B或Cheader标题在顶部时如何得到y位置值。

_onScroll(event) {
    let offset = event.nativeEvent.contentOffset;
    console.log(offset.y);  // y position value
  }

如有任何帮助,我们将不胜感激。

您可以使用 onLayout 获取 A、B 和 C 的初始 y 位置,例如在您的 onScroll 中检查当滚动的 y 位置 - A.y 为 0 时,这将是当前 header 在顶部

方法如下:

https://facebook.github.io/react-native/docs/view#onlayout