Authored by 于良

升级rn版本 review by 孙凯

'use strict';
import {Platform} from 'react-native';
import Community from './community/Community';
// import Community from './community/Community';
import Plustar from './plustar/Plustar';
import Coupon from './coupon/Coupon';
import QRCode from './qrcode/QRCode';
... ... @@ -56,7 +56,7 @@ export default function native(platform) {
PersonalInfo(platform);
if (Platform.OS === 'ios') {
Community(platform);
// Community(platform);
QRCode(platform);
} else {
... ...
/**
* Copyright (c) 2013-present, Facebook, Inc.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* Facebook, Inc. ("Facebook") owns all right, title and interest, including
* all intellectual property and other proprietary rights, in and to the React
* Native CustomComponents software (the "Software"). Subject to your
* compliance with these terms, you are hereby granted a non-exclusive,
* worldwide, royalty-free copyright license to (1) use and copy the Software;
* and (2) reproduce and distribute the Software as part of your own software
* ("Your Software"). Facebook reserves all rights not expressly granted to
* you in this license agreement.
*
* THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
* IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
* EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @providesModule ListView
* @flow
*/
'use strict';
var ListViewDataSource = require('ListViewDataSource');
var Platform = require('Platform');
var React = require('React');
var ReactNative = require('react/lib/ReactNative');
var PropTypes = require('prop-types');
var ReactNative = require('ReactNative');
var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
var ScrollView = require('ScrollView');
var ScrollResponder = require('ScrollResponder');
var StaticRenderer = require('StaticRenderer');
var TimerMixin = require('react-timer-mixin');
var View = require('View');
var cloneReferencedElement = require('react-clone-referenced-element');
var isEmpty = require('isEmpty');
var merge = require('merge');
var PropTypes = React.PropTypes;
var DEFAULT_PAGE_SIZE = 1;
var DEFAULT_INITIAL_ROWS = 10;
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
... ... @@ -56,7 +36,7 @@ var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
/**
* ListView - A core component designed for efficient display of vertically
* scrolling lists of changing data. The minimal API is to create a
* scrolling lists of changing data. The minimal API is to create a
* [`ListView.DataSource`](docs/listviewdatasource.html), populate it with a simple
* array of data blobs, and instantiate a `ListView` component with that data
* source and a `renderRow` callback which takes a blob from the data array and
... ... @@ -65,21 +45,24 @@ var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
* Minimal example:
*
* ```
* getInitialState: function() {
* var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
* return {
* dataSource: ds.cloneWithRows(['row 1', 'row 2']),
* };
* },
* class MyComponent extends Component {
* constructor() {
* super();
* const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
* this.state = {
* dataSource: ds.cloneWithRows(['row 1', 'row 2']),
* };
* }
*
* render: function() {
* return (
* <ListView
* dataSource={this.state.dataSource}
* renderRow={(rowData) => <Text>{rowData}</Text>}
* />
* );
* },
* render() {
* return (
* <ListView
* dataSource={this.state.dataSource}
* renderRow={(rowData) => <Text>{rowData}</Text>}
* />
* );
* }
* }
* ```
*
* ListView also supports more advanced features, including sections with sticky
... ... @@ -97,7 +80,7 @@ var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
* source data has changed - see ListViewDataSource for more details.
*
* * Rate-limited row rendering - By default, only one row is rendered per
* event-loop (customizable with the `pageSize` prop). This breaks up the
* event-loop (customizable with the `pageSize` prop). This breaks up the
* work into smaller chunks to reduce the chance of dropping frames while
* rendering rows.
*/
... ... @@ -142,7 +125,7 @@ var ListView = React.createClass({
* (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
* 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. ListView can be notified when a row is
* being highlighted by calling `highlightRow(sectionID, rowID)`. This
... ... @@ -152,14 +135,14 @@ var ListView = React.createClass({
*/
renderRow: PropTypes.func.isRequired,
/**
* How many rows to render on initial component mount. Use this to make
* How many rows to render on initial component mount. Use this to make
* it so that the first screen worth of data appears at one time instead of
* over the course of multiple frames.
*/
initialListSize: PropTypes.number.isRequired,
/**
* Called when all rows have been rendered and the list has been scrolled
* to within onEndReachedThreshold of the bottom. The native scroll
* to within onEndReachedThreshold of the bottom. The native scroll
* event is provided.
*/
onEndReached: PropTypes.func,
... ... @@ -179,8 +162,8 @@ var ListView = React.createClass({
* () => renderable
*
* The header and footer are always rendered (if these props are provided)
* on every render pass. If they are expensive to re-render, wrap them
* in StaticContainer or other mechanism as appropriate. Footer is always
* on every render pass. If they are expensive to re-render, wrap them
* in StaticContainer or other mechanism as appropriate. Footer is always
* at the bottom of the list, and header at the top, on every render pass.
*/
renderFooter: PropTypes.func,
... ... @@ -188,11 +171,7 @@ var ListView = React.createClass({
/**
* (sectionData, sectionID) => renderable
*
* If provided, a sticky header is rendered for this section. The sticky
* behavior means that it will scroll with the content at the top of the
* section until it reaches the top of the screen, at which point it will
* stick to the top until it is pushed off the screen by the next section
* header.
* If provided, a header is rendered for this section.
*/
renderSectionHeader: PropTypes.func,
/**
... ... @@ -201,35 +180,43 @@ var ListView = React.createClass({
* A function that returns the scrollable component in which the list rows
* are rendered. Defaults to returning a ScrollView with the given props.
*/
renderScrollComponent: React.PropTypes.func.isRequired,
renderScrollComponent: PropTypes.func.isRequired,
/**
* How early to start rendering rows before they come on screen, in
* pixels.
*/
scrollRenderAheadDistance: React.PropTypes.number.isRequired,
scrollRenderAheadDistance: PropTypes.number.isRequired,
/**
* (visibleRows, changedRows) => void
*
* Called when the set of visible rows changes. `visibleRows` maps
* Called when the set of visible rows changes. `visibleRows` maps
* { sectionID: { rowID: true }} for all the visible rows, and
* `changedRows` maps { sectionID: { rowID: true | false }} for the rows
* that have changed their visibility, with true indicating visible, and
* false indicating the view has moved out of view.
*/
onChangeVisibleRows: React.PropTypes.func,
onChangeVisibleRows: PropTypes.func,
/**
* A performance optimization for improving scroll perf of
* large lists, used in conjunction with overflow: 'hidden' on the row
* containers. This is enabled by default.
* containers. This is enabled by default.
*/
removeClippedSubviews: PropTypes.bool,
/**
* Makes the sections headers sticky. The sticky behavior means that it
* will scroll with the content at the top of the section until it reaches
* the top of the screen, at which point it will stick to the top until it
* is pushed off the screen by the next section header. This property is
* not supported in conjunction with `horizontal={true}`. Only enabled by
* default on iOS because of typical platform standards.
*/
removeClippedSubviews: React.PropTypes.bool,
stickySectionHeadersEnabled: PropTypes.bool,
/**
* An array of child indices determining which children get docked to the
* top of the screen when scrolling. For example, passing
* `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
* top of the scroll view. This property is not supported in conjunction
* with `horizontal={true}`.
* @platform ios
*/
stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number).isRequired,
/**
... ... @@ -240,6 +227,13 @@ var ListView = React.createClass({
enableEmptySections: PropTypes.bool,
},
yh_updateVisibleSubViews: function() {
if (this._scrollComponent && this._scrollComponent.yh_updateVisibleSubViews) {
this._scrollComponent.yh_updateVisibleSubViews();
}
},
/**
* Exports some data, e.g. for perf investigations or analytics.
*/
... ... @@ -263,6 +257,14 @@ var ListView = React.createClass({
}
},
getScrollableNode: function() {
if (this._scrollComponent && this._scrollComponent.getScrollableNode) {
return this._scrollComponent.getScrollableNode();
} else {
return ReactNative.findNodeHandle(this._scrollComponent);
}
},
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
... ... @@ -274,9 +276,26 @@ var ListView = React.createClass({
}
},
yh_updateVisibleSubViews: function() {
if (this._scrollComponent && this._scrollComponent.yh_updateVisibleSubViews) {
this._scrollComponent.yh_updateVisibleSubViews();
/**
* If this is a vertical ListView scrolls to the bottom.
* If this is a horizontal ListView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*
* See `ScrollView#scrollToEnd`.
*/
scrollToEnd: function(options?: ?{ animated?: ?boolean }) {
if (this._scrollComponent) {
if (this._scrollComponent.scrollToEnd) {
this._scrollComponent.scrollToEnd(options);
} else {
console.warn(
'The scroll component used by the ListView does not support ' +
'scrollToEnd. Check the renderScrollComponent prop of your ListView.'
);
}
}
},
... ... @@ -297,6 +316,7 @@ var ListView = React.createClass({
renderScrollComponent: props => <ScrollView {...props} />,
scrollRenderAheadDistance: DEFAULT_SCROLL_RENDER_AHEAD,
onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
stickySectionHeadersEnabled: Platform.OS === 'ios',
stickyHeaderIndices: [],
};
},
... ... @@ -367,7 +387,9 @@ var ListView = React.createClass({
var dataSource = this.props.dataSource;
var allRowIDs = dataSource.rowIdentities;
var rowCount = 0;
var sectionHeaderIndices = [];
var stickySectionHeaderIndices = [];
const {renderSectionHeader} = this.props;
var header = this.props.renderHeader && this.props.renderHeader();
var footer = this.props.renderFooter && this.props.renderFooter();
... ... @@ -392,21 +414,18 @@ var ListView = React.createClass({
}
}
if (this.props.renderSectionHeader) {
var shouldUpdateHeader = rowCount >= this._prevRenderedRowsCount &&
dataSource.sectionHeaderShouldUpdate(sectionIdx);
bodyComponents.push(
<StaticRenderer
key={'s_' + sectionID}
shouldUpdate={!!shouldUpdateHeader}
render={this.props.renderSectionHeader.bind(
null,
dataSource.getSectionHeaderData(sectionIdx),
sectionID
)}
/>
if (renderSectionHeader) {
const element = renderSectionHeader(
dataSource.getSectionHeaderData(sectionIdx),
sectionID
);
sectionHeaderIndices.push(totalIndex++);
if (element) {
bodyComponents.push(React.cloneElement(element, {key: 's_' + sectionID}));
if (this.props.stickySectionHeadersEnabled) {
stickySectionHeaderIndices.push(totalIndex);
}
totalIndex++;
}
}
for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
... ... @@ -442,7 +461,11 @@ var ListView = React.createClass({
adjacentRowHighlighted
);
if (separator) {
bodyComponents.push(separator);
bodyComponents.push(
<View key={'s_' + comboID}>
{separator}
</View>
);
totalIndex++;
}
}
... ... @@ -457,7 +480,7 @@ var ListView = React.createClass({
var {
renderScrollComponent,
...props,
...props
} = this.props;
if (!props.scrollEventThrottle) {
props.scrollEventThrottle = DEFAULT_SCROLL_CALLBACK_THROTTLE;
... ... @@ -467,7 +490,7 @@ var ListView = React.createClass({
}
Object.assign(props, {
onScroll: this._onScroll,
stickyHeaderIndices: this.props.stickyHeaderIndices.concat(sectionHeaderIndices),
stickyHeaderIndices: this.props.stickyHeaderIndices.concat(stickySectionHeaderIndices),
// Do not pass these events downstream to ScrollView since they will be
// registered in ListView's own ScrollResponder.Mixin
... ...
... ... @@ -11,26 +11,31 @@
*/
'use strict';
const Animated = require('Animated');
const ColorPropType = require('ColorPropType');
const EdgeInsetsPropType = require('EdgeInsetsPropType');
const Platform = require('Platform');
const PointPropType = require('PointPropType');
const RCTScrollViewManager = require('NativeModules').ScrollViewManager;
const PropTypes = require('prop-types');
const React = require('React');
const ReactNative = require('react/lib/ReactNative');
const ReactNative = require('ReactNative');
const ScrollResponder = require('ScrollResponder');
const ScrollViewStickyHeader = require('ScrollViewStickyHeader');
const StyleSheet = require('StyleSheet');
const StyleSheetPropType = require('StyleSheetPropType');
const View = require('View');
const ViewPropTypes = require('ViewPropTypes');
const ViewStylePropTypes = require('ViewStylePropTypes');
const dismissKeyboard = require('dismissKeyboard');
const flattenStyle = require('flattenStyle');
const invariant = require('fbjs/lib/invariant');
const processDecelerationRate = require('processDecelerationRate');
const PropTypes = React.PropTypes;
const requireNativeComponent = require('requireNativeComponent');
const RCTScrollViewManager = require('NativeModules').ScrollViewManager;
/**
* Component that wraps platform ScrollView while providing
* integration with touch locking "responder" system.
... ... @@ -45,10 +50,31 @@ const requireNativeComponent = require('requireNativeComponent');
*
* Doesn't yet support other contained responders from blocking this scroll
* view from becoming the responder.
*
*
* `<ScrollView>` vs [`<FlatList>`](/react-native/docs/flatlist.html) - which one to use?
*
* `ScrollView` simply renders all its react child components at once. That
* makes it very easy to understand and use.
*
* On the other hand, this has a performance downside. Imagine you have a very
* long list of items you want to display, maybe several screens worth of
* content. Creating JS components and native views for everything all at once,
* much of which may not even be shown, will contribute to slow rendering and
* increased memory usage.
*
* This is where `FlatList` comes into play. `FlatList` renders items lazily,
* just when they are about to appear, and removes items that scroll way off
* screen to save memory and processing time.
*
* `FlatList` is also handy if you want to render separators between your items,
* multiple columns, infinite scroll loading, or any number of other features it
* supports out of the box.
*/
// $FlowFixMe(>=0.41.0)
const ScrollView = React.createClass({
propTypes: {
...View.propTypes,
...ViewPropTypes,
/**
* Controls whether iOS should automatically adjust the content inset
* for scroll views that are placed behind a navigation bar or
... ... @@ -143,8 +169,8 @@ const ScrollView = React.createClass({
/**
* The style of the scroll indicators.
* - `default` (the default), same as `black`.
* - `black`, scroll indicator is black. This style is good against a white content background.
* - `white`, scroll indicator is white. This style is good against a black content background.
* - `black`, scroll indicator is black. This style is good against a light background.
* - `white`, scroll indicator is white. This style is good against a dark background.
* @platform ios
*/
indicatorStyle: PropTypes.oneOf([
... ... @@ -178,12 +204,18 @@ const ScrollView = React.createClass({
'on-drag',
]),
/**
* When false, tapping outside of the focused text input when the keyboard
* is up dismisses the keyboard. When true, the keyboard will not dismiss
* automatically, and the scroll view will not catch taps, but children of
* the scroll view can catch taps. The default value is false.
* Determines when the keyboard should stay visible after a tap.
*
* - 'never' (the default), tapping outside of the focused text input when the keyboard
* is up dismisses the keyboard. When this happens, children won't receive the tap.
* - 'always', the keyboard will not dismiss automatically, and the scroll view will not
* catch taps, but children of the scroll view can catch taps.
* - 'handled', the keyboard will not dismiss automatically when the tap was handled by
* a children, (or captured by an ancestor).
* - false, deprecated, use 'never' instead
* - true, deprecated, use 'always' instead
*/
keyboardShouldPersistTaps: PropTypes.bool,
keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]),
/**
* The maximum allowed zoom scale. The default value is 1.0.
* @platform ios
... ... @@ -207,7 +239,8 @@ const ScrollView = React.createClass({
/**
* Called when scrollable content view of the ScrollView changes.
*
* Handler function is passed the content width and content height as parameters: `(contentWidth, contentHeight)`
* Handler function is passed the content width and content height as parameters:
* `(contentWidth, contentHeight)`
*
* It's implemented using onLayout handler attached to the content container
* which this ScrollView renders.
... ... @@ -252,10 +285,12 @@ const ScrollView = React.createClass({
scrollsToTop: PropTypes.bool,
/**
* When true, shows a horizontal scroll indicator.
* The default value is true.
*/
showsHorizontalScrollIndicator: PropTypes.bool,
/**
* When true, shows a vertical scroll indicator.
* The default value is true.
*/
showsVerticalScrollIndicator: PropTypes.bool,
/**
... ... @@ -264,7 +299,6 @@ const ScrollView = React.createClass({
* `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
* top of the scroll view. This property is not supported in conjunction
* with `horizontal={true}`.
* @platform ios
*/
stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
style: StyleSheetPropType(ViewStylePropTypes),
... ... @@ -304,7 +338,8 @@ const ScrollView = React.createClass({
/**
* A RefreshControl component, used to provide pull-to-refresh
* functionality for the ScrollView.
* functionality for the ScrollView. Only works for vertical ScrollViews
* (`horizontal` prop must be `false`).
*
* See [RefreshControl](docs/refreshcontrol.html).
*/
... ... @@ -328,6 +363,25 @@ const ScrollView = React.createClass({
*/
scrollPerfTag: PropTypes.string,
/**
* Used to override default value of overScroll mode.
*
* Possible values:
*
* - `'auto'` - Default value, allow a user to over-scroll
* this view only if the content is large enough to meaningfully scroll.
* - `'always'` - Always allow a user to over-scroll this view.
* - `'never'` - Never allow a user to over-scroll this view.
*
* @platform android
*/
overScrollMode: PropTypes.oneOf([
'auto',
'always',
'never',
]),
/**
pull to refresh
... ... @@ -343,19 +397,27 @@ const ScrollView = React.createClass({
*/
yh_exposureData: PropTypes.any,
yh_viewVisible: PropTypes.bool,
},
mixins: [ScrollResponder.Mixin],
_scrollAnimatedValue: (new Animated.Value(0): Animated.Value),
_scrollAnimatedValueAttachment: (null: ?{detach: () => void}),
_stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>),
_headerLayoutYs: (new Map(): Map<string, number>),
yh_updateVisibleSubViews: function() {
RCTScrollViewManager.yh_updateVisibleSubViews(
ReactNative.findNodeHandle(this)
ReactNative.findNodeHandle(this._scrollViewRef)
);
},
startPullToRefresh: function() {
RCTScrollViewManager.startPullToRefresh(
ReactNative.findNodeHandle(this)
ReactNative.findNodeHandle(this._scrollViewRef)
);
},
... ... @@ -365,10 +427,31 @@ const ScrollView = React.createClass({
);
},
getInitialState: function() {
return this.scrollResponderMixinGetInitialState();
},
componentWillMount: function() {
this._scrollAnimatedValue = new Animated.Value(0);
this._stickyHeaderRefs = new Map();
this._headerLayoutYs = new Map();
},
componentDidMount: function() {
this._updateAnimatedNodeAttachment();
},
componentDidUpdate: function() {
this._updateAnimatedNodeAttachment();
},
componentWillUnmount: function() {
if (this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment.detach();
}
},
setNativeProps: function(props: Object) {
this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
},
... ... @@ -394,12 +477,12 @@ const ScrollView = React.createClass({
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* Syntax:
* Example:
*
* `scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})`
* `scrollTo({x: 0, y: 0, animated: true})`
*
* Note: The weird argument signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as as alternative to the options object.
* Note: The weird function signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as an alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
scrollTo: function(
... ... @@ -408,24 +491,97 @@ const ScrollView = React.createClass({
animated?: boolean
) {
if (typeof y === 'number') {
console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.');
console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
'animated: true})` instead.');
} else {
({x, y, animated} = y || {});
}
this.getScrollResponder().scrollResponderScrollTo({x: x || 0, y: y || 0, animated: animated !== false});
this.getScrollResponder().scrollResponderScrollTo(
{x: x || 0, y: y || 0, animated: animated !== false}
);
},
/**
* If this is a vertical ScrollView scrolls to the bottom.
* If this is a horizontal ScrollView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*/
scrollToEnd: function(
options?: { animated?: boolean },
) {
// Default to true
const animated = (options && options.animated) !== false;
this.getScrollResponder().scrollResponderScrollToEnd({
animated: animated,
});
},
/**
* Deprecated, do not use.
* Deprecated, use `scrollTo` instead.
*/
scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
this.scrollTo({x, y, animated: false});
},
_getKeyForIndex: function(index, childArray) {
const child = childArray[index];
return child && child.key;
},
_updateAnimatedNodeAttachment: function() {
if (this.props.stickyHeaderIndices && this.props.stickyHeaderIndices.length > 0) {
if (!this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment = Animated.attachNativeEvent(
this._scrollViewRef,
'onScroll',
[{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}]
);
}
} else {
if (this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment.detach();
}
}
},
_setStickyHeaderRef: function(key, ref) {
if (ref) {
this._stickyHeaderRefs.set(key, ref);
} else {
this._stickyHeaderRefs.delete(key);
}
},
_onStickyHeaderLayout: function(index, event, key) {
if (!this.props.stickyHeaderIndices) {
return;
}
const childArray = React.Children.toArray(this.props.children);
if (key !== this._getKeyForIndex(index, childArray)) {
// ignore stale layout update
return;
}
const layoutY = event.nativeEvent.layout.y;
this._headerLayoutYs.set(key, layoutY);
const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index);
const previousHeaderIndex = this.props.stickyHeaderIndices[indexOfIndex - 1];
if (previousHeaderIndex != null) {
const previousHeader = this._stickyHeaderRefs.get(
this._getKeyForIndex(previousHeaderIndex, childArray)
);
previousHeader && previousHeader.setNextHeaderY(layoutY);
}
},
_handleScroll: function(e: Object) {
if (__DEV__) {
if (this.props.onScroll && !this.props.scrollEventThrottle && Platform.OS === 'ios') {
if (this.props.onScroll && this.props.scrollEventThrottle == null && Platform.OS === 'ios') {
console.log( // eslint-disable-line no-console-disallow
'You specified `onScroll` on a <ScrollView> but not ' +
'`scrollEventThrottle`. You will only receive one event. ' +
... ... @@ -459,6 +615,30 @@ const ScrollView = React.createClass({
},
render: function() {
let ScrollViewClass;
let ScrollContentContainerViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;
ScrollContentContainerViewClass = RCTScrollContentView;
} else if (Platform.OS === 'android') {
if (this.props.horizontal) {
ScrollViewClass = AndroidHorizontalScrollView;
} else {
ScrollViewClass = AndroidScrollView;
}
ScrollContentContainerViewClass = View;
}
invariant(
ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined'
);
invariant(
ScrollContentContainerViewClass !== undefined,
'ScrollContentContainerViewClass must not be undefined'
);
const contentContainerStyle = [
this.props.horizontal && styles.contentContainerHorizontal,
this.props.contentContainerStyle,
... ... @@ -482,15 +662,41 @@ const ScrollView = React.createClass({
};
}
const {stickyHeaderIndices} = this.props;
const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0;
const childArray = hasStickyHeaders && React.Children.toArray(this.props.children);
const children = hasStickyHeaders ?
childArray.map((child, index) => {
const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
if (indexOfIndex > -1) {
const key = child.key;
const nextIndex = stickyHeaderIndices[indexOfIndex + 1];
return (
<ScrollViewStickyHeader
key={key}
ref={(ref) => this._setStickyHeaderRef(key, ref)}
nextHeaderLayoutY={
this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray))
}
onLayout={(event) => this._onStickyHeaderLayout(index, event, key)}
scrollAnimatedValue={this._scrollAnimatedValue}>
{child}
</ScrollViewStickyHeader>
);
} else {
return child;
}
}) :
this.props.children;
const contentContainer =
<View
<ScrollContentContainerViewClass
{...contentSizeChangeProps}
ref={this._setInnerViewRef}
style={contentContainerStyle}
removeClippedSubviews={this.props.removeClippedSubviews}
collapsable={false}>
{this.props.children}
</View>;
{children}
</ScrollContentContainerViewClass>;
const alwaysBounceHorizontal =
this.props.alwaysBounceHorizontal !== undefined ?
... ... @@ -508,23 +714,28 @@ const ScrollView = React.createClass({
alwaysBounceHorizontal,
alwaysBounceVertical,
style: ([baseStyle, this.props.style]: ?Array<any>),
onTouchStart: this.scrollResponderHandleTouchStart,
onTouchMove: this.scrollResponderHandleTouchMove,
onTouchEnd: this.scrollResponderHandleTouchEnd,
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
// Override the onContentSizeChange from props, since this event can
// bubble up from TextInputs
onContentSizeChange: null,
onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
onScroll: this._handleScroll,
onResponderGrant: this.scrollResponderHandleResponderGrant,
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
onResponderTerminate: this.scrollResponderHandleTerminate,
onResponderRelease: this.scrollResponderHandleResponderRelease,
onResponderReject: this.scrollResponderHandleResponderReject,
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ? true : false,
onResponderRelease: this.scrollResponderHandleResponderRelease,
onResponderTerminate: this.scrollResponderHandleTerminate,
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
onScroll: this._handleScroll,
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
onTouchEnd: this.scrollResponderHandleTouchEnd,
onTouchMove: this.scrollResponderHandleTouchMove,
onTouchStart: this.scrollResponderHandleTouchStart,
scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle,
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ?
true : false,
};
const { decelerationRate } = this.props;
... ... @@ -532,28 +743,15 @@ const ScrollView = React.createClass({
props.decelerationRate = processDecelerationRate(decelerationRate);
}
let ScrollViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;
} else if (Platform.OS === 'android') {
if (this.props.horizontal) {
ScrollViewClass = AndroidHorizontalScrollView;
} else {
ScrollViewClass = AndroidScrollView;
}
}
invariant(
ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined'
);
const refreshControl = this.props.refreshControl;
if (refreshControl) {
if (Platform.OS === 'ios') {
// On iOS the RefreshControl is a child of the ScrollView.
// tvOS lacks native support for RefreshControl, so don't include it in that case
return (
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
{refreshControl}
{Platform.isTVOS ? null : refreshControl}
{contentContainer}
</ScrollViewClass>
);
... ... @@ -561,6 +759,9 @@ const ScrollView = React.createClass({
// On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
// Since the ScrollView is wrapped add the style props to the
// AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
// Note: we should only apply props.style on the wrapper
// however, the ScrollView still needs the baseStyle to be scrollable
return React.cloneElement(
refreshControl,
{style: props.style},
... ... @@ -580,29 +781,41 @@ const ScrollView = React.createClass({
const styles = StyleSheet.create({
baseVertical: {
flex: 1,
flexGrow: 1,
flexShrink: 1,
flexDirection: 'column',
overflow: 'scroll',
},
baseHorizontal: {
flex: 1,
flexGrow: 1,
flexShrink: 1,
flexDirection: 'row',
overflow: 'scroll',
},
contentContainerHorizontal: {
flexDirection: 'row',
},
});
let nativeOnlyProps, AndroidScrollView, AndroidHorizontalScrollView, RCTScrollView;
let nativeOnlyProps,
AndroidScrollView,
AndroidHorizontalScrollView,
RCTScrollView,
RCTScrollContentView;
if (Platform.OS === 'android') {
nativeOnlyProps = {
nativeOnly: {
sendMomentumEvents: true,
}
};
AndroidScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
AndroidScrollView = requireNativeComponent(
'RCTScrollView',
(ScrollView: ReactClass<any>),
nativeOnlyProps
);
AndroidHorizontalScrollView = requireNativeComponent(
'AndroidHorizontalScrollView',
ScrollView,
(ScrollView: ReactClass<any>),
nativeOnlyProps
);
} else if (Platform.OS === 'ios') {
... ... @@ -614,7 +827,12 @@ if (Platform.OS === 'android') {
onScrollEndDrag: true,
}
};
RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
RCTScrollView = requireNativeComponent(
'RCTScrollView',
(ScrollView: ReactClass<any>),
nativeOnlyProps,
);
RCTScrollContentView = requireNativeComponent('RCTScrollContentView', View);
}
module.exports = ScrollView;
... ...
... ... @@ -14,25 +14,26 @@
// Note (avik): add @flow when Flow supports spread properties in propTypes
var ColorPropType = require('ColorPropType');
var NativeMethodsMixin = require('react/lib/NativeMethodsMixin');
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
const PropTypes = require('prop-types');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var TimerMixin = require('react-timer-mixin');
var Touchable = require('Touchable');
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
var View = require('View');
const ViewPropTypes = require('ViewPropTypes');
var ensureComponentIsNative = require('ensureComponentIsNative');
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
var keyOf = require('fbjs/lib/keyOf');
var merge = require('merge');
var onlyChild = require('react/lib/onlyChild');
type Event = Object;
var DEFAULT_PROPS = {
activeOpacity: 0.8,
activeOpacity: 0.85,
underlayColor: 'black',
};
... ... @@ -41,10 +42,15 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
/**
* A wrapper for making views respond properly to touches.
* On press down, the opacity of the wrapped view is decreased, which allows
* the underlay color to show through, darkening or tinting the view. The
* underlay comes from adding a view to the view hierarchy, which can sometimes
* cause unwanted visual artifacts if not used correctly, for example if the
* backgroundColor of the wrapped view isn't explicitly set to an opaque color.
* the underlay color to show through, darkening or tinting the view.
*
* The underlay comes from wrapping the child in a new View, which can affect
* layout, and sometimes cause unwanted visual artifacts if not used correctly,
* for example if the backgroundColor of the wrapped view isn't explicitly set
* to an opaque color.
*
* TouchableHighlight must have one child (not zero or more than one).
* If you wish to have several child components, wrap them in a View.
*
* Example:
*
... ... @@ -60,9 +66,6 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
* );
* },
* ```
* > **NOTE**: TouchableHighlight supports only one child
* >
* > If you wish to have several child components, wrap them in a View.
*/
var TouchableHighlight = React.createClass({
... ... @@ -72,21 +75,39 @@ var TouchableHighlight = React.createClass({
* Determines what the opacity of the wrapped view should be when touch is
* active.
*/
activeOpacity: React.PropTypes.number,
activeOpacity: PropTypes.number,
/**
* The color of the underlay that will show through when the touch is
* active.
*/
underlayColor: ColorPropType,
style: View.propTypes.style,
style: ViewPropTypes.style,
/**
* Called immediately after the underlay is shown
*/
onShowUnderlay: React.PropTypes.func,
onShowUnderlay: PropTypes.func,
/**
* Called immediately after the underlay is hidden
*/
onHideUnderlay: React.PropTypes.func,
onHideUnderlay: PropTypes.func,
/**
* *(Apple TV only)* TV preferred focus (see documentation for the View component).
*
* @platform ios
*/
hasTVPreferredFocus: PropTypes.bool,
/**
* *(Apple TV only)* Object with properties to control Apple TV parallax effects.
*
* enabled: If true, parallax effects are enabled. Defaults to true.
* shiftDistanceX: Defaults to 2.0.
* shiftDistanceY: Defaults to 2.0.
* tiltAngle: Defaults to 0.05.
* magnification: Defaults to 1.0.
*
* @platform ios
*/
tvParallaxProperties: PropTypes.object,
yh_exposureData: React.PropTypes.object,
... ... @@ -112,7 +133,8 @@ var TouchableHighlight = React.createClass({
underlayStyle: [
INACTIVE_UNDERLAY_PROPS.style,
props.style,
]
],
hasTVPreferredFocus: props.hasTVPreferredFocus
};
},
... ... @@ -239,15 +261,19 @@ var TouchableHighlight = React.createClass({
style={this.state.underlayStyle}
onLayout={this.props.onLayout}
hitSlop={this.props.hitSlop}
isTVSelectable={true}
tvParallaxProperties={this.props.tvParallaxProperties}
hasTVPreferredFocus={this.state.hasTVPreferredFocus}
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
onResponderGrant={this.touchableHandleResponderGrant}
onResponderMove={this.touchableHandleResponderMove}
onResponderRelease={this.touchableHandleResponderRelease}
onResponderTerminate={this.touchableHandleResponderTerminate}
nativeID={this.props.nativeID}
testID={this.props.testID}>
{React.cloneElement(
onlyChild(this.props.children),
React.Children.only(this.props.children),
{
ref: CHILD_REF,
}
... ...
... ... @@ -14,8 +14,10 @@
// Note (avik): add @flow when Flow supports spread properties in propTypes
var Animated = require('Animated');
var NativeMethodsMixin = require('react/lib/NativeMethodsMixin');
var Easing = require('Easing');
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
var PropTypes = require('prop-types');
var TimerMixin = require('react-timer-mixin');
var Touchable = require('Touchable');
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
... ... @@ -30,8 +32,9 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
/**
* A wrapper for making views respond properly to touches.
* On press down, the opacity of the wrapped view is decreased, dimming it.
* This is done without actually changing the view hierarchy, and in general is
* easy to add to an app without weird side-effects.
*
* Opacity is controlled by wrapping the children in an Animated.View, which is
* added to the view hiearchy. Be aware that this can affect layout.
*
* Example:
*
... ... @@ -57,22 +60,27 @@ var TouchableOpacity = React.createClass({
* Determines what the opacity of the wrapped view should be when touch is
* active. Defaults to 0.2.
*/
activeOpacity: React.PropTypes.number,
activeOpacity: PropTypes.number,
focusedOpacity: PropTypes.number,
/**
* Apple TV parallax effects
*/
tvParallaxProperties: PropTypes.object,
yh_exposureData: React.PropTypes.object,
},
getDefaultProps: function() {
return {
activeOpacity: 0.2,
focusedOpacity: 0.7,
};
},
getInitialState: function() {
return {
...this.touchableGetInitialState(),
anim: new Animated.Value(1),
anim: new Animated.Value(this._getChildStyleOpacityWithDefault()),
};
},
... ... @@ -87,10 +95,15 @@ var TouchableOpacity = React.createClass({
/**
* Animate the touchable to a new opacity.
*/
setOpacityTo: function(value: number) {
setOpacityTo: function(value: number, duration: number) {
Animated.timing(
this.state.anim,
{toValue: value, duration: 150}
{
toValue: value,
duration: duration,
easing: Easing.inOut(Easing.quad),
useNativeDriver: true,
}
).start();
},
... ... @@ -99,26 +112,20 @@ var TouchableOpacity = React.createClass({
* defined on your component.
*/
touchableHandleActivePressIn: function(e: Event) {
this.clearTimeout(this._hideTimeout);
this._hideTimeout = null;
this._opacityActive();
if (e.dispatchConfig.registrationName === 'onResponderGrant') {
this._opacityActive(0);
} else {
this._opacityActive(150);
}
this.props.onPressIn && this.props.onPressIn(e);
},
touchableHandleActivePressOut: function(e: Event) {
if (!this._hideTimeout) {
this._opacityInactive();
}
this._opacityInactive(250);
this.props.onPressOut && this.props.onPressOut(e);
},
touchableHandlePress: function(e: Event) {
this.clearTimeout(this._hideTimeout);
this._opacityActive();
this._hideTimeout = this.setTimeout(
this._opacityInactive,
this.props.delayPressOut || 100
);
this.props.onPress && this.props.onPress(e);
},
... ... @@ -147,37 +154,47 @@ var TouchableOpacity = React.createClass({
return this.props.delayPressOut;
},
_opacityActive: function() {
this.setOpacityTo(this.props.activeOpacity);
_opacityActive: function(duration: number) {
this.setOpacityTo(this.props.activeOpacity, duration);
},
_opacityInactive: function() {
this.clearTimeout(this._hideTimeout);
this._hideTimeout = null;
var childStyle = flattenStyle(this.props.style) || {};
_opacityInactive: function(duration: number) {
this.setOpacityTo(
childStyle.opacity === undefined ? 1 : childStyle.opacity
this._getChildStyleOpacityWithDefault(),
duration
);
},
_opacityFocused: function() {
this.setOpacityTo(this.props.focusedOpacity);
},
_getChildStyleOpacityWithDefault: function() {
var childStyle = flattenStyle(this.props.style) || {};
return childStyle.opacity == undefined ? 1 : childStyle.opacity;
},
render: function() {
return (
<Animated.View
yh_exposureData={this.props.yh_exposureData}
accessible={this.props.accessible !== false}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
style={[this.props.style, {opacity: this.state.anim}]}
nativeID={this.props.nativeID}
testID={this.props.testID}
onLayout={this.props.onLayout}
isTVSelectable={true}
tvParallaxProperties={this.props.tvParallaxProperties}
hitSlop={this.props.hitSlop}
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
onResponderGrant={this.touchableHandleResponderGrant}
onResponderMove={this.touchableHandleResponderMove}
onResponderRelease={this.touchableHandleResponderRelease}
onResponderTerminate={this.touchableHandleResponderTerminate}
yh_exposureData={this.props.yh_exposureData}>
onResponderTerminate={this.touchableHandleResponderTerminate}>
{this.props.children}
{Touchable.renderDebugView({color: 'cyan', hitSlop: this.props.hitSlop})}
</Animated.View>
... ...
... ... @@ -11,65 +11,34 @@
*/
'use strict';
const EdgeInsetsPropType = require('EdgeInsetsPropType');
const NativeMethodsMixin = require('react/lib/NativeMethodsMixin');
const PropTypes = require('react/lib/ReactPropTypes');
const NativeMethodsMixin = require('NativeMethodsMixin');
const NativeModules = require('NativeModules');
const Platform = require('Platform');
const React = require('React');
const PropTypes = require('prop-types');
const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const StyleSheetPropType = require('StyleSheetPropType');
const UIManager = require('UIManager');
const ViewStylePropTypes = require('ViewStylePropTypes');
const ViewPropTypes = require('ViewPropTypes');
const requireNativeComponent = require('requireNativeComponent');
const stylePropType = StyleSheetPropType(ViewStylePropTypes);
const invariant = require('fbjs/lib/invariant');
const warning = require('fbjs/lib/warning');
const AccessibilityTraits = [
'none',
'button',
'link',
'header',
'search',
'image',
'selected',
'plays',
'key',
'text',
'summary',
'disabled',
'frequentUpdates',
'startsMedia',
'adjustable',
'allowsDirectInteraction',
'pageTurn',
];
const {
AccessibilityComponentTypes,
AccessibilityTraits,
} = require('ViewAccessibility');
const AccessibilityComponentType = [
'none',
'button',
'radiobutton_checked',
'radiobutton_unchecked',
];
const requireNativeComponent = require('requireNativeComponent');
const forceTouchAvailable = (UIManager.RCTView.Constants &&
UIManager.RCTView.Constants.forceTouchAvailable) || false;
const statics = {
AccessibilityTraits,
AccessibilityComponentType,
/**
* Is 3D Touch / Force Touch available (i.e. will touch events include `force`)
* @platform ios
*/
forceTouchAvailable,
};
const forceTouchAvailable = (NativeModules.PlatformConstants &&
NativeModules.PlatformConstants.forceTouchAvailable) || false;
/**
* The most fundamental component for building a UI, `View` is a container that supports layout with
* [flexbox](/react-native/docs/flexbox.html), [style](/react-native/docs/style.html),
* [some touch handling](/react-native/docs/handling-touches.html), and
* [accessibility](/react-native/docs/accessibility.html) controls. `View` maps directly to the
* [flexbox](docs/flexbox.html), [style](docs/style.html),
* [some touch handling](docs/handling-touches.html), and
* [accessibility](docs/accessibility.html) controls. `View` maps directly to the
* native view equivalent on whatever platform React Native is running on, whether that is a
* `UIView`, `<div>`, `android.view`, etc.
*
... ... @@ -92,12 +61,12 @@ const statics = {
* }
* ```
*
* > `View`s are designed to be used with [`StyleSheet`](/react-native/docs/style.html) for clarity
* > `View`s are designed to be used with [`StyleSheet`](docs/style.html) for clarity
* > and performance, although inline styles are also supported.
*
* ### Synthetic Touch Events
*
* For `View` repsonder props (e.g., `onResponderMove`), the synthetic touch event passed to them
* For `View` responder props (e.g., `onResponderMove`), the synthetic touch event passed to them
* are of the following form:
*
* - `nativeEvent`
... ... @@ -111,6 +80,7 @@ const statics = {
* - `timestamp` - A time identifier for the touch, useful for velocity calculation.
* - `touches` - Array of all current touches on the screen.
*/
// $FlowFixMe(>=0.41.0)
const View = React.createClass({
// TODO: We should probably expose the mixins, viewConfig, and statics publicly. For example,
// one of the props is of type AccessibilityComponentType. That is defined as a const[] above,
... ... @@ -118,6 +88,27 @@ const View = React.createClass({
// values had to be hardcoded.
mixins: [NativeMethodsMixin],
// `propTypes` should not be accessed directly on View since this wrapper only
// exists for DEV mode. However it's important for them to be declared.
// If the object passed to `createClass` specifies `propTypes`, Flow will
// create a static type from it. This property will be over-written below with
// a warn-on-use getter though.
// TODO (bvaughn) Remove the warn-on-use comment after April 1.
propTypes: {
yh_exposureData: PropTypes.object,
yh_viewVisible: PropTypes.bool,
...ViewPropTypes
},
// ReactElementValidator will (temporarily) use this private accessor when
// detected to avoid triggering the warning message.
// TODO (bvaughn) Remove this after April 1 ReactNative RC is tagged.
statics: {
__propTypesSecretDontUseThesePlease: ViewPropTypes
},
/**
* `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We
* make `this` look like an actual native component class.
... ... @@ -127,384 +118,15 @@ const View = React.createClass({
validAttributes: ReactNativeViewAttributes.RCTView
},
statics: {
...statics,
},
propTypes: {
/**
* When `true`, indicates that the view is an accessibility element. By default,
* all the touchable elements are accessible.
*/
accessible: PropTypes.bool,
/**
* Overrides the text that's read by the screen reader when the user interacts
* with the element. By default, the label is constructed by traversing all the
* children and accumulating all the `Text` nodes separated by space.
*/
accessibilityLabel: PropTypes.string,
/**
* Indicates to accessibility services to treat UI component like a
* native one. Works for Android only.
*
* Possible values are one of:
*
* - `'none'`
* - `'button'`
* - `'radiobutton_checked'`
* - `'radiobutton_unchecked'`
*
* @platform android
*/
accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentType),
/**
* Indicates to accessibility services whether the user should be notified
* when this view changes. Works for Android API >= 19 only.
* Possible values:
*
* - `'none'` - Accessibility services should not announce changes to this view.
* - `'polite'`- Accessibility services should announce changes to this view.
* - `'assertive'` - Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
*
* See the [Android `View` docs](http://developer.android.com/reference/android/view/View.html#attr_android:accessibilityLiveRegion)
* for reference.
*
* @platform android
*/
accessibilityLiveRegion: PropTypes.oneOf([
'none',
'polite',
'assertive',
]),
/**
* Controls how view is important for accessibility which is if it
* fires accessibility events and if it is reported to accessibility services
* that query the screen. Works for Android only.
*
* Possible values:
*
* - `'auto'` - The system determines whether the view is important for accessibility -
* default (recommended).
* - `'yes'` - The view is important for accessibility.
* - `'no'` - The view is not important for accessibility.
* - `'no-hide-descendants'` - The view is not important for accessibility,
* nor are any of its descendant views.
*
* See the [Android `importantForAccessibility` docs](http://developer.android.com/reference/android/R.attr.html#importantForAccessibility)
* for reference.
*
* @platform android
*/
importantForAccessibility: PropTypes.oneOf([
'auto',
'yes',
'no',
'no-hide-descendants',
]),
/**
* Provides additional traits to screen reader. By default no traits are
* provided unless specified otherwise in element.
*
* You can provide one trait or an array of many traits.
*
* Possible values for `AccessibilityTraits` are:
*
* - `'none'` - The element has no traits.
* - `'button'` - The element should be treated as a button.
* - `'link'` - The element should be treated as a link.
* - `'header'` - The element is a header that divides content into sections.
* - `'search'` - The element should be treated as a search field.
* - `'image'` - The element should be treated as an image.
* - `'selected'` - The element is selected.
* - `'plays'` - The element plays sound.
* - `'key'` - The element should be treated like a keyboard key.
* - `'text'` - The element should be treated as text.
* - `'summary'` - The element provides app summary information.
* - `'disabled'` - The element is disabled.
* - `'frequentUpdates'` - The element frequently changes its value.
* - `'startsMedia'` - The element starts a media session.
* - `'adjustable'` - The element allows adjustment over a range of values.
* - `'allowsDirectInteraction'` - The element allows direct touch interaction for VoiceOver users.
* - `'pageTurn'` - Informs VoiceOver that it should scroll to the next page when it finishes reading the contents of the element.
*
* See the [Accessibility guide](/react-native/docs/accessibility.html#accessibilitytraits-ios)
* for more information.
*
* @platform ios
*/
accessibilityTraits: PropTypes.oneOfType([
PropTypes.oneOf(AccessibilityTraits),
PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
]),
/**
* When `accessible` is true, the system will try to invoke this function
* when the user performs accessibility tap gesture.
*/
onAccessibilityTap: PropTypes.func,
/**
* When `accessible` is `true`, the system will invoke this function when the
* user performs the magic tap gesture.
*/
onMagicTap: PropTypes.func,
/**
* Used to locate this view in end-to-end tests.
*
* > This disables the 'layout-only view removal' optimization for this view!
*/
testID: PropTypes.string,
/**
* For most touch interactions, you'll simply want to wrap your component in
* `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
* `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
*/
/**
* The View is now responding for touch events. This is the time to highlight and show the user
* what is happening.
*
* `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderGrant: PropTypes.func,
/**
* The user is moving their finger.
*
* `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderMove: PropTypes.func,
/**
* Another responder is already active and will not release it to that `View` asking to be
* the responder.
*
* `View.props.onResponderReject: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderReject: PropTypes.func,
/**
* Fired at the end of the touch.
*
* `View.props.onResponderRelease: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderRelease: PropTypes.func,
/**
* The responder has been taken from the `View`. Might be taken by other views after a call to
* `onResponderTerminationRequest`, or might be taken by the OS without asking (e.g., happens
* with control center/ notification center on iOS)
*
* `View.props.onResponderTerminate: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderTerminate: PropTypes.func,
/**
* Some other `View` wants to become responder and is asking this `View` to release its
* responder. Returning `true` allows its release.
*
* `View.props.onResponderTerminationRequest: (event) => {}`, where `event` is a synthetic touch
* event as described above.
*/
onResponderTerminationRequest: PropTypes.func,
/**
* Does this view want to become responder on the start of a touch?
*
* `View.props.onStartShouldSetResponder: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onStartShouldSetResponder: PropTypes.func,
/**
* If a parent `View` wants to prevent a child `View` from becoming responder on a touch start,
* it should have this handler which returns `true`.
*
* `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onStartShouldSetResponderCapture: PropTypes.func,
/**
* Does this view want to "claim" touch responsiveness? This is called for every touch move on
* the `View` when it is not the responder.
*
* `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onMoveShouldSetResponder: PropTypes.func,
/**
* If a parent `View` wants to prevent a child `View` from becoming responder on a move,
* it should have this handler which returns `true`.
*
* `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onMoveShouldSetResponderCapture: PropTypes.func,
/**
* This defines how far a touch event can start away from the view.
* Typical interface guidelines recommend touch targets that are at least
* 30 - 40 points/density-independent pixels.
*
* For example, if a touchable view has a height of 20 the touchable height can be extended to
* 40 with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`
*
* > The touch area never extends past the parent view bounds and the Z-index
* > of sibling views always takes precedence if a touch hits two overlapping
* > views.
*/
hitSlop: EdgeInsetsPropType,
/**
* Invoked on mount and layout changes with:
*
* `{nativeEvent: { layout: {x, y, width, height}}}`
*
* This event is fired immediately once the layout has been calculated, but
* the new layout may not yet be reflected on the screen at the time the
* event is received, especially if a layout animation is in progress.
*/
onLayout: PropTypes.func,
/**
* Controls whether the `View` can be the target of touch events.
*
* - `'auto'`: The View can be the target of touch events.
* - `'none'`: The View is never the target of touch events.
* - `'box-none'`: The View is never the target of touch events but it's
* subviews can be. It behaves like if the view had the following classes
* in CSS:
* ```
* .box-none {
* pointer-events: none;
* }
* .box-none * {
* pointer-events: all;
* }
* ```
* - `'box-only'`: The view can be the target of touch events but it's
* subviews cannot be. It behaves like if the view had the following classes
* in CSS:
* ```
* .box-only {
* pointer-events: all;
* }
* .box-only * {
* pointer-events: none;
* }
* ```
* > Since `pointerEvents` does not affect layout/appearance, and we are
* > already deviating from the spec by adding additional modes, we opt to not
* > include `pointerEvents` on `style`. On some platforms, we would need to
* > implement it as a `className` anyways. Using `style` or not is an
* > implementation detail of the platform.
*/
pointerEvents: PropTypes.oneOf([
'box-none',
'none',
'box-only',
'auto',
]),
style: stylePropType,
/**
* This is a special performance property exposed by `RCTView` and is useful
* for scrolling content when there are many subviews, most of which are
* offscreen. For this property to be effective, it must be applied to a
* view that contains many subviews that extend outside its bound. The
* subviews must also have `overflow: hidden`, as should the containing view
* (or one of its superviews).
*/
removeClippedSubviews: PropTypes.bool,
/**
* Whether this `View` should render itself (and all of its children) into a
* single hardware texture on the GPU.
*
* On Android, this is useful for animations and interactions that only
* modify opacity, rotation, translation, and/or scale: in those cases, the
* view doesn't have to be redrawn and display lists don't need to be
* re-executed. The texture can just be re-used and re-composited with
* different parameters. The downside is that this can use up limited video
* memory, so this prop should be set back to false at the end of the
* interaction/animation.
*
* @platform android
*/
renderToHardwareTextureAndroid: PropTypes.bool,
/**
* Whether this `View` should be rendered as a bitmap before compositing.
*
* On iOS, this is useful for animations and interactions that do not
* modify this component's dimensions nor its children; for example, when
* translating the position of a static view, rasterization allows the
* renderer to reuse a cached bitmap of a static view and quickly composite
* it during each frame.
*
* Rasterization incurs an off-screen drawing pass and the bitmap consumes
* memory. Test and measure when using this property.
*
* @platform ios
*/
shouldRasterizeIOS: PropTypes.bool,
/**
* Views that are only used to layout their children or otherwise don't draw
* anything may be automatically removed from the native hierarchy as an
* optimization. Set this property to `false` to disable this optimization and
* ensure that this `View` exists in the native view hierarchy.
*
* @platform android
*/
collapsable: PropTypes.bool,
/**
* Whether this `View` needs to rendered offscreen and composited with an alpha
* in order to preserve 100% correct colors and blending behavior. The default
* (`false`) falls back to drawing the component and its children with an alpha
* applied to the paint used to draw each element instead of rendering the full
* component offscreen and compositing it back with an alpha value. This default
* may be noticeable and undesired in the case where the `View` you are setting
* an opacity on has multiple overlapping elements (e.g. multiple overlapping
* `View`s, or text and a background).
*
* Rendering offscreen to preserve correct alpha behavior is extremely
* expensive and hard to debug for non-native developers, which is why it is
* not turned on by default. If you do need to enable this property for an
* animation, consider combining it with renderToHardwareTextureAndroid if the
* view **contents** are static (i.e. it doesn't need to be redrawn each frame).
* If that property is enabled, this View will be rendered off-screen once,
* saved in a hardware texture, and then composited onto the screen with an alpha
* each frame without having to switch rendering targets on the GPU.
*
* @platform android
*/
needsOffscreenAlphaCompositing: PropTypes.bool,
yh_exposureData: PropTypes.object,
yh_viewVisible: PropTypes.bool,
contextTypes: {
isInAParentText: PropTypes.bool,
},
render: function() {
invariant(
!(this.context.isInAParentText && Platform.OS === 'android'),
'Nesting of <View> within <Text> is not supported on Android.');
// WARNING: This method will not be used in production mode as in that mode we
// replace wrapper component View with generated native wrapper RCTView. Avoid
// adding functionality this component that you'd want to be available in both
... ... @@ -513,13 +135,79 @@ const View = React.createClass({
},
});
// Warn about unsupported use of View static properties as these will no longer
// be supported with React fiber. This warning message will go away in the next
// ReactNative release. Use defineProperty() rather than createClass() statics
// because the mixin process auto-triggers the 1-time warning message.
// TODO (bvaughn) Remove this after April 1 ReactNative RC is tagged.
function mixinStatics (target) {
let warnedAboutAccessibilityTraits = false;
let warnedAboutAccessibilityComponentType = false;
let warnedAboutForceTouchAvailable = false;
let warnedAboutPropTypes = false;
// $FlowFixMe https://github.com/facebook/flow/issues/285
Object.defineProperty(target, 'AccessibilityTraits', {
get: function() {
warning(
warnedAboutAccessibilityTraits,
'View.AccessibilityTraits has been deprecated and will be ' +
'removed in a future version of ReactNative. Use ' +
'ViewAccessibility.AccessibilityTraits instead.'
);
warnedAboutAccessibilityTraits = true;
return AccessibilityTraits;
}
});
// $FlowFixMe https://github.com/facebook/flow/issues/285
Object.defineProperty(target, 'AccessibilityComponentType', {
get: function() {
warning(
warnedAboutAccessibilityComponentType,
'View.AccessibilityComponentType has been deprecated and will be ' +
'removed in a future version of ReactNative. Use ' +
'ViewAccessibility.AccessibilityComponentTypes instead.'
);
warnedAboutAccessibilityComponentType = true;
return AccessibilityComponentTypes;
}
});
// $FlowFixMe https://github.com/facebook/flow/issues/285
Object.defineProperty(target, 'forceTouchAvailable', {
get: function() {
warning(
warnedAboutForceTouchAvailable,
'View.forceTouchAvailable has been deprecated and will be removed ' +
'in a future version of ReactNative. Use ' +
'NativeModules.PlatformConstants.forceTouchAvailable instead.'
);
warnedAboutForceTouchAvailable = true;
return forceTouchAvailable;
}
});
// $FlowFixMe https://github.com/facebook/flow/issues/285
Object.defineProperty(target, 'propTypes', {
get: function() {
warning(
warnedAboutPropTypes,
'View.propTypes has been deprecated and will be removed in a future ' +
'version of ReactNative. Use ViewPropTypes instead.'
);
warnedAboutPropTypes = true;
return ViewPropTypes;
}
});
}
const RCTView = requireNativeComponent('RCTView', View, {
nativeOnly: {
nativeBackgroundAndroid: true,
nativeForegroundAndroid: true,
}
});
if (__DEV__) {
const UIManager = require('UIManager');
const viewConfig = UIManager.viewConfigs && UIManager.viewConfigs.RCTView || {};
for (const prop in viewConfig.nativeProps) {
const viewAny: any = View; // Appease flow
... ... @@ -531,11 +219,21 @@ if (__DEV__) {
}
}
// TODO (bvaughn) Remove feature flags once all static View accessors are gone.
// We temporarily wrap fiber native views with the create-class View above,
// Because external code sometimes accesses static properties of this view.
let ViewToExport = RCTView;
if (__DEV__) {
if (
__DEV__ ||
ReactNativeFeatureFlags.useFiber
) {
mixinStatics(View);
ViewToExport = View;
} else {
Object.assign(RCTView, statics);
// TODO (bvaughn) Remove this mixin once all static View accessors are gone.
mixinStatics((RCTView : any));
}
module.exports = ViewToExport;
// TODO (bvaughn) Temporarily mask Flow warnings for View property accesses.
// We're wrapping the string type (Fiber) for now to avoid any actual problems.
module.exports = ((ViewToExport : any) : typeof View);
... ...
... ... @@ -16,14 +16,13 @@
"moment": "^2.13.0",
"object-assign": "^4.1.0",
"query-string": "^4.2.2",
"react": "15.3.1",
"react": "^16.0.0-alpha.6",
"react-immutable-proptypes": "^2.1.0",
"react-native": "0.32.0",
"react-native": "git+https://github.com/facebook/react-native.git#32eab54",
"react-native-device-info": "0.9.5",
"react-native-fabric": "0.2.2",
"react-native-progress": "^3.0.1",
"react-native-root-toast": "^1.0.3",
"react-native-router-flux": "^3.32.0",
"react-native-scrollable-mixin": "^1.0.1",
"react-native-simple-store": "^1.1.0",
"react-native-smart-toast": "^1.1.1",
... ... @@ -39,4 +38,4 @@
"timeago.js": "^1.0.5",
"yh_rncamera": "0.1.0"
}
}
}
... ...
... ... @@ -6,7 +6,7 @@ cp -f ./js/common/components/customComponents/View.js.bak ./node_modules/react-n
echo "Replace ScrollView.js..."
cp -f ./js/common/components/customComponents/ScrollView.js.bak ./node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
echo "Replace ListView.js..."
cp -f ./js/common/components/customComponents/ListView.js.bak ./node_modules/react-native/Libraries/CustomComponents/ListView/ListView.js
cp -f ./js/common/components/customComponents/ListView.js.bak ./node_modules/react-native/Libraries/Lists/ListView/ListView.js
echo "Replace TouchableOpacity.js..."
cp -f ./js/common/components/customComponents/TouchableOpacity.js.bak ./node_modules/react-native/Libraries/Components/Touchable/TouchableOpacity.js
echo "Replace TouchableHighlight.js..."
... ...