Apple TV: Enable long presses on TV remote; dev menu on TV device; example code

Summary:
**Motivation**

Properly support long presses on the Apple TV remote, and also enable dev menu functionality on a real Apple TV device (shaking an Apple TV doesn't work 😄 )

**Test plan**

New example added to `RNTester`.
Closes https://github.com/facebook/react-native/pull/15221

Differential Revision: D5526463

Pulled By: javache

fbshipit-source-id: a61051e86bc82a9561eefc1704bed6b1f2617e05
This commit is contained in:
Douglas Lowder 2017-07-31 03:53:09 -07:00 committed by Facebook Github Bot
parent e61257cd0a
commit 75284d3cd4
6 changed files with 142 additions and 4 deletions

View File

@ -336,6 +336,11 @@ const APIExamples: Array<RNTesterExample> = [
module: require('./TransformExample'),
supportsTVOS: true,
},
{
key: 'TVEventHandlerExample',
module: require('./TVEventHandlerExample'),
supportsTVOS: true,
},
{
key: 'VibrationExample',
module: require('./VibrationExample'),

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2017-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.
*
* @flow
* @providesModule TVEventHandlerExample
*/
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var {
Platform,
StyleSheet,
View,
Text,
TouchableOpacity,
TVEventHandler,
} = ReactNative;
exports.framework = 'React';
exports.title = 'TVEventHandler example';
exports.description = 'iOS alerts and action sheets';
exports.examples = [{
title: 'TVEventHandler',
render() {return <TVEventHandlerView/>;}
}];
class TVEventHandlerView extends React.Component {
state: {
lastEventType: string
}
constructor(props) {
super(props);
this.state = {
lastEventType: ''
};
}
_tvEventHandler: any;
_enableTVEventHandler() {
this._tvEventHandler = new TVEventHandler();
this._tvEventHandler.enable(this, function(cmp, evt) {
cmp.setState({
lastEventType: evt.eventType
})
});
}
_disableTVEventHandler() {
if (this._tvEventHandler) {
this._tvEventHandler.disable();
delete this._tvEventHandler;
}
}
componentDidMount() {
this._enableTVEventHandler();
}
componentWillUnmount() {
this._disableTVEventHandler();
}
render() {
if (Platform.isTVOS) {
return (
<View>
<TouchableOpacity onPress={() => {}}>
<Text>
This example enables an instance of TVEventHandler to show the last event detected from the Apple TV Siri remote or from a keyboard.
</Text>
</TouchableOpacity>
<Text style={{color: 'blue'}}>
{this.state.lastEventType}
</Text>
</View>
);
} else {
return (
<View>
<Text>
This example is intended to be run on Apple TV.
</Text>
</View>
);
}
}
}

View File

@ -22,6 +22,8 @@
#import "RCTView.h"
#import "UIView+React.h"
#import "RCTDevMenu.h"
@implementation RCTTVRemoteHandler {
NSMutableArray<UIGestureRecognizer *> *_tvRemoteGestureRecognizers;
}
@ -61,6 +63,14 @@
[self addTapGestureRecognizerWithSelector:@selector(swipedRight:)
pressType:UIPressTypeRightArrow];
// Recognizers for long button presses
// We don't intercept long menu press -- that's used by the system to go to the home screen
[self addLongPressGestureRecognizerWithSelector:@selector(longPlayPausePressed:)
pressType:UIPressTypePlayPause];
[self addLongPressGestureRecognizerWithSelector:@selector(longSelectPressed:)
pressType:UIPressTypeSelect];
// Recognizers for Apple TV remote trackpad swipes
@ -100,9 +110,19 @@
[self sendAppleTVEvent:@"select" toView:r.view];
}
- (void)longPress:(UIGestureRecognizer *)r
- (void)longPlayPausePressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:@"longPress" toView:r.view];
[self sendAppleTVEvent:@"longPlayPause" toView:r.view];
// If shake to show is enabled on device, use long play/pause event to show dev menu
#if RCT_DEV
[[NSNotificationCenter defaultCenter] postNotificationName:RCTShowDevMenuNotification object:nil];
#endif
}
- (void)longSelectPressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:@"longSelect" toView:r.view];
}
- (void)swipedUp:(UIGestureRecognizer *)r
@ -127,6 +147,14 @@
#pragma mark -
- (void)addLongPressGestureRecognizerWithSelector:(nonnull SEL)selector pressType:(UIPressType)pressType
{
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:selector];
recognizer.allowedPressTypes = @[@(pressType)];
[_tvRemoteGestureRecognizers addObject:recognizer];
}
- (void)addTapGestureRecognizerWithSelector:(nonnull SEL)selector pressType:(UIPressType)pressType
{
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:selector];

View File

@ -12,6 +12,13 @@
#import <React/RCTBridge.h>
#import <React/RCTBridgeModule.h>
#if RCT_DEV
RCT_EXTERN NSString *const RCTShowDevMenuNotification;
#endif
@class RCTDevMenuItem;
/**

View File

@ -16,7 +16,7 @@
#if RCT_DEV
static NSString *const RCTShowDevMenuNotification = @"RCTShowDevMenuNotification";
NSString *const RCTShowDevMenuNotification = @"RCTShowDevMenuNotification";
@implementation UIWindow (RCTDevMenu)

View File

@ -83,6 +83,7 @@ class Game2048 extends React.Component {
}
```
- *Dev Menu support*: On the simulator, cmd-D will bring up the developer menu, just like on iOS. To bring it up on a real Apple TV device, make a long press on the play/pause button on the remote. (Please do not shake the Apple TV device, that will not work :) )
- *TV remote animations*: `RCTTVView` native code implements Apple-recommended parallax animations to help guide the eye as the user navigates through views. The animations can be disabled or adjusted with new optional view properties.