Skip to content

Commit 6c353fd

Browse files
JulienKodefacebook-github-bot
authored andcommitted
onPress animation with magnification
Summary: Related to: facebook#15454 Motivation: Improve tvOS feeling for TouchableHighlight ![changewithaniamtion](https://user-images.githubusercontent.com/7658664/29193477-b99b4a10-7e25-11e7-8b31-e0e4ca9d7720.gif) - When you select the button he is focus and the underlay is show - When you press the button, there is an animation, but after the animation, the focus is on the button and the underlay is show Play with tvParallaxProperties on tvOS, test with and without patch just to see the actual behaviour ``` <TouchableHighlight tvParallaxProperties={{ enabled: true, shiftDistanceX: 0, shiftDistanceY: 0, tiltAngle: 0, magnification: 1.1, pressMagnification: 1.0, pressDuration: 0.3, }} underlayColor="black" onShowUnderlay={() => (console.log("onShowUnderlay")} onHideUnderlay={() => (console.log("onHideUnderlay")} onPress={() => (console.log("onPress")} > <Image style={styles.image} source={ uri: 'https://www.facebook.com/images/fb_icon_325x325.png' } /> </TouchableHighlight> ``` Closes facebook#15455 Differential Revision: D6887437 Pulled By: hramos fbshipit-source-id: e18b695068bc99643ba4006fb3f39215b38a74c1
1 parent 1346bf8 commit 6c353fd

File tree

6 files changed

+95
-23
lines changed

6 files changed

+95
-23
lines changed

Libraries/Components/AppleTV/TVViewPropTypes.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ var TVViewPropTypes = {
3737
* shiftDistanceY: Defaults to 2.0.
3838
* tiltAngle: Defaults to 0.05.
3939
* magnification: Defaults to 1.0.
40+
* pressMagnification: Defaults to 1.0.
41+
* pressDuration: Defaults to 0.3.
42+
* pressDelay: Defaults to 0.0.
4043
*
4144
* @platform ios
4245
*/

Libraries/Components/Touchable/TouchableHighlight.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
const ColorPropType = require('ColorPropType');
1414
const NativeMethodsMixin = require('NativeMethodsMixin');
1515
const PropTypes = require('prop-types');
16+
const Platform = require('Platform');
1617
const React = require('React');
1718
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
1819
const StyleSheet = require('StyleSheet');
@@ -172,6 +173,9 @@ const TouchableHighlight = createReactClass({
172173
* shiftDistanceY: Defaults to 2.0.
173174
* tiltAngle: Defaults to 0.05.
174175
* magnification: Defaults to 1.0.
176+
* pressMagnification: Defaults to 1.0.
177+
* pressDuration: Defaults to 0.3.
178+
* pressDelay: Defaults to 0.0.
175179
*
176180
* @platform ios
177181
*/
@@ -246,11 +250,13 @@ const TouchableHighlight = createReactClass({
246250

247251
touchableHandlePress: function(e: PressEvent) {
248252
clearTimeout(this._hideTimeout);
249-
this._showUnderlay();
250-
this._hideTimeout = setTimeout(
251-
this._hideUnderlay,
252-
this.props.delayPressOut,
253-
);
253+
if (!Platform.isTVOS) {
254+
this._showUnderlay();
255+
this._hideTimeout = setTimeout(
256+
this._hideUnderlay,
257+
this.props.delayPressOut,
258+
);
259+
}
254260
this.props.onPress && this.props.onPress(e);
255261
},
256262

RNTester/js/ListExampleShared.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class ItemComponent extends React.PureComponent<{
6262
onPress={this._onPress}
6363
onShowUnderlay={this.props.onShowUnderlay}
6464
onHideUnderlay={this.props.onHideUnderlay}
65+
tvParallaxProperties={{
66+
pressMagnification: 1.1,
67+
}}
6568
style={horizontal ? styles.horizItem : styles.item}>
6669
<View style={[
6770
styles.row, horizontal && {width: HORIZ_WIDTH}, fixedHeight && {height: ITEM_HEIGHT}]}>

RNTester/js/RNTesterList.ios.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ const ComponentExamples: Array<RNTesterExample> = [
189189
{
190190
key: 'TouchableExample',
191191
module: require('./TouchableExample'),
192-
supportsTVOS: false,
192+
supportsTVOS: true,
193193
},
194194
{
195195
key: 'TransparentHitTestExample',

RNTester/js/TouchableExample.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ exports.examples = [
5555
style={styles.wrapper}
5656
activeOpacity={1}
5757
animationVelocity={0}
58+
tvParallaxProperties={{pressMagnification: 1.3, pressDuration: 0.6}}
5859
underlayColor="rgb(210, 230, 255)"
5960
onPress={() => console.log('custom THW text - highlight')}>
6061
<View style={styles.wrapperCustom}>

React/Views/RCTTVView.m

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,50 @@ @implementation RCTTVView
2727
- (instancetype)initWithFrame:(CGRect)frame
2828
{
2929
if (self = [super initWithFrame:frame]) {
30-
self.tvParallaxProperties = @{
31-
@"enabled": @YES,
32-
@"shiftDistanceX": @2.0f,
33-
@"shiftDistanceY": @2.0f,
34-
@"tiltAngle": @0.05f,
35-
@"magnification": @1.0f
36-
};
30+
dispatch_once(&onceToken, ^{
31+
defaultTVParallaxProperties = @{
32+
@"enabled": @YES,
33+
@"shiftDistanceX": @2.0f,
34+
@"shiftDistanceY": @2.0f,
35+
@"tiltAngle": @0.05f,
36+
@"magnification": @1.0f,
37+
@"pressMagnification": @1.0f,
38+
@"pressDuration": @0.3f,
39+
@"pressDelay": @0.0f
40+
};
41+
});
42+
self.tvParallaxProperties = defaultTVParallaxProperties;
3743
}
3844

3945
return self;
4046
}
4147

48+
static NSDictionary* defaultTVParallaxProperties = nil;
49+
static dispatch_once_t onceToken;
50+
51+
- (void)setTvParallaxProperties:(NSDictionary *)tvParallaxProperties {
52+
if (_tvParallaxProperties == nil) {
53+
_tvParallaxProperties = [defaultTVParallaxProperties copy];
54+
return;
55+
}
56+
57+
NSMutableDictionary *newParallaxProperties = [NSMutableDictionary dictionaryWithDictionary:_tvParallaxProperties];
58+
for (NSString *k in [defaultTVParallaxProperties allKeys]) {
59+
if (tvParallaxProperties[k]) {
60+
newParallaxProperties[k] = tvParallaxProperties[k];
61+
}
62+
}
63+
_tvParallaxProperties = [newParallaxProperties copy];
64+
}
65+
4266
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused)
4367

4468
- (void)setIsTVSelectable:(BOOL)isTVSelectable {
4569
self->_isTVSelectable = isTVSelectable;
46-
if(isTVSelectable) {
47-
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSelect:)];
70+
if (isTVSelectable) {
71+
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc]
72+
initWithTarget:self
73+
action:@selector(handleSelect:)];
4874
recognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
4975
_selectRecognizer = recognizer;
5076
[self addGestureRecognizer:_selectRecognizer];
@@ -57,8 +83,37 @@ - (void)setIsTVSelectable:(BOOL)isTVSelectable {
5783

5884
- (void)handleSelect:(__unused UIGestureRecognizer *)r
5985
{
60-
[[NSNotificationCenter defaultCenter] postNotificationName:RCTTVNavigationEventNotification
61-
object:@{@"eventType":@"select",@"tag":self.reactTag}];
86+
if ([self.tvParallaxProperties[@"enabled"] boolValue] == YES) {
87+
float magnification = [self.tvParallaxProperties[@"magnification"] floatValue];
88+
float pressMagnification = [self.tvParallaxProperties[@"pressMagnification"] floatValue];
89+
90+
// Duration of press animation
91+
float pressDuration = [self.tvParallaxProperties[@"pressDuration"] floatValue];
92+
93+
// Delay of press animation
94+
float pressDelay = [self.tvParallaxProperties[@"pressDelay"] floatValue];
95+
96+
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:pressDelay]];
97+
98+
[UIView animateWithDuration:(pressDuration/2)
99+
animations:^{
100+
self.transform = CGAffineTransformMakeScale(pressMagnification, pressMagnification);
101+
}
102+
completion:^(__unused BOOL finished1){
103+
[UIView animateWithDuration:(pressDuration/2)
104+
animations:^{
105+
self.transform = CGAffineTransformMakeScale(magnification, magnification);
106+
}
107+
completion:^(__unused BOOL finished2) {
108+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTTVNavigationEventNotification
109+
object:@{@"eventType":@"select",@"tag":self.reactTag}];
110+
}];
111+
}];
112+
113+
} else {
114+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTTVNavigationEventNotification
115+
object:@{@"eventType":@"select",@"tag":self.reactTag}];
116+
}
62117
}
63118

64119
- (BOOL)isUserInteractionEnabled
@@ -79,23 +134,25 @@ - (void)addParallaxMotionEffects
79134

80135
// Make horizontal movements shift the centre left and right
81136
UIInterpolatingMotionEffect *xShift = [[UIInterpolatingMotionEffect alloc]
82-
initWithKeyPath:@"center.x"
83-
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
137+
initWithKeyPath:@"center.x"
138+
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
84139
xShift.minimumRelativeValue = @( shiftDistanceX * -1.0f);
85140
xShift.maximumRelativeValue = @( shiftDistanceX);
86141

87142
// Make vertical movements shift the centre up and down
88143
UIInterpolatingMotionEffect *yShift = [[UIInterpolatingMotionEffect alloc]
89-
initWithKeyPath:@"center.y"
90-
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
144+
initWithKeyPath:@"center.y"
145+
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
91146
yShift.minimumRelativeValue = @( shiftDistanceY * -1.0f);
92147
yShift.maximumRelativeValue = @( shiftDistanceY);
93148

94149
// Size of tilt movements
95150
CGFloat const tiltAngle = [self.tvParallaxProperties[@"tiltAngle"] floatValue];
96151

97152
// Now make horizontal movements effect a rotation about the Y axis for side-to-side rotation.
98-
UIInterpolatingMotionEffect *xTilt = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
153+
UIInterpolatingMotionEffect *xTilt = [[UIInterpolatingMotionEffect alloc]
154+
initWithKeyPath:@"layer.transform"
155+
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
99156

100157
// CATransform3D value for minimumRelativeValue
101158
CATransform3D transMinimumTiltAboutY = CATransform3DIdentity;
@@ -112,7 +169,9 @@ - (void)addParallaxMotionEffects
112169
xTilt.maximumRelativeValue = [NSValue valueWithCATransform3D: transMaximumTiltAboutY];
113170

114171
// Now make vertical movements effect a rotation about the X axis for up and down rotation.
115-
UIInterpolatingMotionEffect *yTilt = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
172+
UIInterpolatingMotionEffect *yTilt = [[UIInterpolatingMotionEffect alloc]
173+
initWithKeyPath:@"layer.transform"
174+
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
116175

117176
// CATransform3D value for minimumRelativeValue
118177
CATransform3D transMinimumTiltAboutX = CATransform3DIdentity;

0 commit comments

Comments
 (0)