/** * 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. * * @providesModule TouchableOpacity * @noflow */ 'use strict'; // Note (avik): add @flow when Flow supports spread properties in propTypes var Animated = require('Animated'); var Easing = require('Easing'); var NativeMethodsMixin = require('NativeMethodsMixin'); var React = require('React'); var TimerMixin = require('react-timer-mixin'); var Touchable = require('Touchable'); var TouchableWithoutFeedback = require('TouchableWithoutFeedback'); var ensurePositiveDelayProps = require('ensurePositiveDelayProps'); var flattenStyle = require('flattenStyle'); type Event = Object; 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. * * 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: * * ``` * renderButton: function() { * return ( * * * * ); * }, * ``` */ var TouchableOpacity = React.createClass({ mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin], propTypes: { ...TouchableWithoutFeedback.propTypes, /** * Determines what the opacity of the wrapped view should be when touch is * active. Defaults to 0.2. */ activeOpacity: React.PropTypes.number, focusedOpacity: React.PropTypes.number, /** * Apple TV parallax effects */ tvParallaxProperties: React.PropTypes.object, }, getDefaultProps: function() { return { activeOpacity: 0.2, focusedOpacity: 0.7, }; }, getInitialState: function() { return { ...this.touchableGetInitialState(), anim: new Animated.Value(this._getChildStyleOpacityWithDefault()), }; }, componentDidMount: function() { ensurePositiveDelayProps(this.props); }, componentWillReceiveProps: function(nextProps) { ensurePositiveDelayProps(nextProps); }, /** * Animate the touchable to a new opacity. */ setOpacityTo: function(value: number, duration: number) { Animated.timing( this.state.anim, { toValue: value, duration: duration, easing: Easing.inOut(Easing.quad), useNativeDriver: true, } ).start(); }, /** * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ touchableHandleActivePressIn: function(e: Event) { if (e.dispatchConfig.registrationName === 'onResponderGrant') { this._opacityActive(0); } else { this._opacityActive(150); } this.props.onPressIn && this.props.onPressIn(e); }, touchableHandleActivePressOut: function(e: Event) { this._opacityInactive(250); this.props.onPressOut && this.props.onPressOut(e); }, touchableHandlePress: function(e: Event) { this.props.onPress && this.props.onPress(e); }, touchableHandleLongPress: function(e: Event) { this.props.onLongPress && this.props.onLongPress(e); }, touchableGetPressRectOffset: function() { return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET; }, touchableGetHitSlop: function() { return this.props.hitSlop; }, touchableGetHighlightDelayMS: function() { return this.props.delayPressIn || 0; }, touchableGetLongPressDelayMS: function() { return this.props.delayLongPress === 0 ? 0 : this.props.delayLongPress || 500; }, touchableGetPressOutDelayMS: function() { return this.props.delayPressOut; }, _opacityActive: function(duration: number) { this.setOpacityTo(this.props.activeOpacity, duration); }, _opacityInactive: function(duration: number) { this.setOpacityTo( 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 ( {this.props.children} {Touchable.renderDebugView({color: 'cyan', hitSlop: this.props.hitSlop})} ); }, }); module.exports = TouchableOpacity;