使用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 在顶部
方法如下:
我想获取每个部分 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 在顶部
方法如下: