Add renderSeparator support to ListView

This commit is contained in:
Changgeng Li 2015-05-26 15:16:42 -07:00
parent b839ab32be
commit 84783dbac4
5 changed files with 112 additions and 7 deletions

View File

@ -34,7 +34,10 @@ var MovieCell = React.createClass({
var criticsScore = this.props.movie.ratings.critics_score;
return (
<View>
<TouchableHighlight onPress={this.props.onSelect}>
<TouchableHighlight
onPress={this.props.onSelect}
onShowUnderlay={this.props.onHighlight}
onHideUnderlay={this.props.onUnhighlight}>
<View style={styles.row}>
<Image
source={getImageSource(this.props.movie, 'det')}
@ -54,7 +57,6 @@ var MovieCell = React.createClass({
</View>
</View>
</TouchableHighlight>
<View style={styles.cellBorder} />
</View>
);
}

View File

@ -16,6 +16,7 @@
140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14312D241AC3654D00CDC950 /* libRCTLinking.a */; };
14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A2D4411AC3E41A00CC738A /* libReact.a */; };
58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5725B1AA6236500CDF9C8 /* libRCTText.a */; };
67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -54,6 +55,13 @@
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
remoteInfo = RCTText;
};
67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
remoteInfo = RCTWebSocket;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@ -69,6 +77,7 @@
14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
14A2D43C1AC3E41A00CC738A /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = "<group>"; };
587650F61A9EB120008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = SOURCE_ROOT; };
67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -76,6 +85,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */,
14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */,
140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */,
1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */,
@ -135,6 +145,7 @@
58C571FC1AA6124500CDF9C8 /* Libraries */ = {
isa = PBXGroup;
children = (
67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */,
14A2D43C1AC3E41A00CC738A /* React.xcodeproj */,
14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */,
134180151AA91740003F314A /* RCTNetwork.xcodeproj */,
@ -152,6 +163,14 @@
name = Products;
sourceTree = "<group>";
};
67C95F161B0E647A0040BCE2 /* Products */ = {
isa = PBXGroup;
children = (
67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */,
);
name = Products;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@ -228,6 +247,10 @@
ProductGroup = 58C572571AA6236500CDF9C8 /* Products */;
ProjectRef = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */;
},
{
ProductGroup = 67C95F161B0E647A0040BCE2 /* Products */;
ProjectRef = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */;
},
{
ProductGroup = 14A2D43D1AC3E41A00CC738A /* Products */;
ProjectRef = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */;
@ -276,6 +299,13 @@
remoteRef = 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTWebSocket.a;
remoteRef = 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */

View File

@ -237,10 +237,31 @@ var SearchScreen = React.createClass({
return <ActivityIndicatorIOS style={styles.scrollSpinner} />;
},
renderRow: function(movie: Object) {
renderSeparator: function(
sectionID: number | string,
rowID: number | string,
adjacentRowHighlighted: boolean
) {
var style = styles.rowSeparator;
if (adjacentRowHighlighted) {
style = [style, styles.rowSeparatorHide];
}
return (
<View key={"SEP_" + sectionID + "_" + rowID} style={style}/>
);
},
renderRow: function(
movie: Object,
sectionID: number | string,
rowID: number | string,
highlightRowFunc: (sectionID: ?number | string, rowID: ?number | string) => void,
) {
return (
<MovieCell
onSelect={() => this.selectMovie(movie)}
onHighlight={() => highlightRowFunc(sectionID, rowID)}
onUnhighlight={() => highlightRowFunc(null, null)}
movie={movie}
/>
);
@ -254,6 +275,7 @@ var SearchScreen = React.createClass({
/> :
<ListView
ref="listview"
renderSeparator={this.renderSeparator}
dataSource={this.state.dataSource}
renderFooter={this.renderFooter}
renderRow={this.renderRow}
@ -352,6 +374,14 @@ var styles = StyleSheet.create({
scrollSpinner: {
marginVertical: 20,
},
rowSeparator: {
backgroundColor: 'rgba(0, 0, 0, 0.1)',
height: 1,
marginLeft: 4,
},
rowSeparatorHide: {
opacity: 0.0,
},
});
module.exports = SearchScreen;

View File

@ -70,6 +70,14 @@ var TouchableHighlight = React.createClass({
*/
underlayColor: React.PropTypes.string,
style: View.propTypes.style,
/**
* Called immediately after the underlay is shown
*/
onShowUnderlay: React.PropTypes.func,
/**
* Called immediately after the underlay is hidden
*/
onHideUnderlay: React.PropTypes.func,
},
mixins: [NativeMethodsMixin, TimerMixin, Touchable.Mixin],
@ -159,6 +167,7 @@ var TouchableHighlight = React.createClass({
_showUnderlay: function() {
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
this.props.onShowUnderlay && this.props.onShowUnderlay();
},
_hideUnderlay: function() {
@ -170,6 +179,7 @@ var TouchableHighlight = React.createClass({
...INACTIVE_UNDERLAY_PROPS,
style: this.state.underlayStyle,
});
this.props.onHideUnderlay && this.props.onHideUnderlay();
}
},

View File

@ -108,7 +108,7 @@ var ListView = React.createClass({
* You must provide a renderRow function. If you omit any of the other render
* functions, ListView will simply skip rendering them.
*
* - renderRow(rowData, sectionID, rowID);
* - renderRow(rowData, sectionID, rowID, highlightRow);
* - renderSectionHeader(sectionData, sectionID);
*/
propTypes: {
@ -116,11 +116,22 @@ var ListView = React.createClass({
dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
/**
* (rowData, sectionID, rowID) => renderable
* (sectionID, rowID, adjacentRowHighlighted) => renderable
* If provided, a renderable component to be rendered as the separator
* below each row but not the last row if there is a section header below.
* Take a sectionID and rowID of the row above and whether its adjacent row
* is highlighted.
*/
renderSeparator: PropTypes.func,
/**
* (rowData, sectionID, rowID, highlightRow) => renderable
* Takes a data entry from the data source and its ids and should return
* a renderable component to be rendered as the row. By default the data
* is exactly what was put into the data source, but it's also possible to
* provide custom extractors.
* provide custom extractors. ListView can be notified when a row is
* being highlighted by calling highlightRow function. The separators above and
* below will be hidden when a row is highlighted. The highlighted state of
* a row can be reset by calling highlightRow(null).
*/
renderRow: PropTypes.func.isRequired,
/**
@ -227,6 +238,7 @@ var ListView = React.createClass({
return {
curRenderedRowsCount: this.props.initialListSize,
prevRenderedRowsCount: 0,
highlightedRow: {},
};
},
@ -256,6 +268,10 @@ var ListView = React.createClass({
}
},
onRowHighlighted: function(sectionID, rowID) {
this.setState({highlightedRow: {sectionID, rowID}});
},
render: function() {
var bodyComponents = [];
@ -305,11 +321,28 @@ var ListView = React.createClass({
null,
dataSource.getRowData(sectionIdx, rowIdx),
sectionID,
rowID
rowID,
this.onRowHighlighted
)}
/>;
bodyComponents.push(row);
totalIndex++;
if (this.props.renderSeparator &&
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length -1)) {
var adjacentRowHighlighted =
this.state.highlightedRow.sectionID === sectionID && (
this.state.highlightedRow.rowID === rowID ||
this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
);
var separator = this.props.renderSeparator(
sectionID,
rowID,
adjacentRowHighlighted
);
bodyComponents.push(separator);
totalIndex++;
}
if (++rowCount === this.state.curRenderedRowsCount) {
break;
}