2015-02-30 update:
- [ReactNative] Fix indentation | Ben Alpert - [ReactKit] Bring back ability to jump to syntax error from redbox | Alex Kotliarskyi - [ReactKit] Update pthread.h import path to be (more?) correct | Ben Alpert - Simplified event handling | Nick Lockwood - [ReactNative] more readme - xcode error help | Spencer Ahrens
This commit is contained in:
parent
0512e23ba9
commit
00f0ebccdf
|
@ -53,6 +53,8 @@ var NavigatorIOSExample = React.createClass({
|
|||
</View>
|
||||
</View>
|
||||
<View style={styles.line}/>
|
||||
<View style={styles.groupSpace}/>
|
||||
<View style={styles.line}/>
|
||||
<View style={styles.group}>
|
||||
{this._renderRow(recurseTitle, () => {
|
||||
this.props.navigator.push({
|
||||
|
@ -182,7 +184,9 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
group: {
|
||||
backgroundColor: 'white',
|
||||
paddingVertical: 10,
|
||||
},
|
||||
groupSpace: {
|
||||
height: 15,
|
||||
},
|
||||
line: {
|
||||
backgroundColor: '#bbbbbb',
|
||||
|
@ -192,7 +196,7 @@ var styles = StyleSheet.create({
|
|||
backgroundColor: 'white',
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 8,
|
||||
paddingVertical: 15,
|
||||
},
|
||||
separator: {
|
||||
height: 1 / PixelRatio.get(),
|
||||
|
|
19
README.md
19
README.md
|
@ -35,10 +35,10 @@ Get up and running with our Movies sample app:
|
|||
|
||||
1. Once you have the repo cloned and met all the requirements above, start the
|
||||
packager that will transform your JS code on-the-fly:
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
2. Open the `Examples/Movies/Movies.xcodeproj` project in Xcode.
|
||||
3. Make sure the target is set to `Movies` and that you have an iOS simulator
|
||||
selected to run the app.
|
||||
|
@ -61,22 +61,19 @@ Feel free to browse the Movies sample files and customize various properties to
|
|||
get familiar with the codebase and React Native.
|
||||
|
||||
Also check out the UI Component Explorer for more sample code:
|
||||
`Examples/UIExplorer/UIExplorer.xcodeproj`. **Make sure to stop any running apps
|
||||
before running a new one or Xcode might hang.**
|
||||
`Examples/UIExplorer/UIExplorer.xcodeproj`. **Make sure to close the Movies
|
||||
project first - Xcode will break if you have two projects open that reference
|
||||
the same library.**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If Xcode hangs, force kill it with the activity monitor. This sometimes happens
|
||||
if you try to run another app without manually stopping the previous one first.
|
||||
Xcode will break if you have two examples open at the same time.
|
||||
|
||||
Jest testing does not yet work on node versions after 0.10.x.
|
||||
|
||||
You can verify the packager is working by loading the [bundle](http://localhost:8081/Examples/Movies/MoviesApp.includeRequire.runModule.bundle) in your browser and
|
||||
inspecting the contents.
|
||||
|
||||
You might see weird npm install errors - we recommend uninstalling and
|
||||
reinstalling node and other software with brew instead.
|
||||
|
||||
Please report any other issues you encounter so we can fix them ASAP.
|
||||
|
||||
## Basics
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
@protocol RCTNativeModule;
|
||||
|
||||
@class RCTUIManager;
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
/**
|
||||
* Functions are the one thing that aren't automatically converted to OBJC
|
||||
|
@ -67,7 +67,7 @@ static inline NSDictionary *RCTAPIErrorObject(NSString *msg)
|
|||
- (void)enqueueUpdateTimers;
|
||||
|
||||
@property (nonatomic, readonly) RCTUIManager *uiManager;
|
||||
@property (nonatomic, readonly) RCTJavaScriptEventDispatcher *eventDispatcher;
|
||||
@property (nonatomic, readonly) RCTEventDispatcher *eventDispatcher;
|
||||
|
||||
// For use in implementing delegates, which may need to queue responses.
|
||||
- (RCTResponseSenderBlock)createResponseSenderBlock:(NSInteger)callbackID;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#import "RCTModuleMethod.h"
|
||||
#import "RCTInvalidating.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTModuleIDs.h"
|
||||
#import "RCTTiming.h"
|
||||
|
@ -94,7 +94,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
_javaScriptExecutor = javaScriptExecutor;
|
||||
_latestJSExecutor = _javaScriptExecutor;
|
||||
_shadowQueue = shadowQueue;
|
||||
_eventDispatcher = [[RCTJavaScriptEventDispatcher alloc] initWithBridge:self];
|
||||
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
||||
|
||||
_moduleInstances = [[NSMutableDictionary alloc] init];
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
||||
RCTTouchEventTypeStart,
|
||||
RCTTouchEventTypeMove,
|
||||
RCTTouchEventTypeEnd,
|
||||
RCTTouchEventTypeCancel
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTTextEventType) {
|
||||
RCTTextEventTypeFocus,
|
||||
RCTTextEventTypeBlur,
|
||||
RCTTextEventTypeChange,
|
||||
RCTTextEventTypeSubmit,
|
||||
RCTTextEventTypeEnd
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTScrollEventType) {
|
||||
RCTScrollEventTypeStart,
|
||||
RCTScrollEventTypeMove,
|
||||
RCTScrollEventTypeEnd,
|
||||
RCTScrollEventTypeStartDeceleration,
|
||||
RCTScrollEventTypeEndDeceleration,
|
||||
RCTScrollEventTypeEndAnimation,
|
||||
};
|
||||
|
||||
@interface RCTEventDispatcher : NSObject
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge;
|
||||
|
||||
/**
|
||||
* Send an arbitrary event type
|
||||
*/
|
||||
- (void)sendRawEventWithType:(NSString *)eventType body:(NSDictionary *)body;
|
||||
|
||||
/**
|
||||
* Send an array of touch events
|
||||
*/
|
||||
- (void)sendTouchEventWithType:(RCTTouchEventType)type
|
||||
touches:(NSArray *)touches
|
||||
changedIndexes:(NSArray *)changedIndexes;
|
||||
|
||||
/**
|
||||
* Send text events
|
||||
*/
|
||||
- (void)sendTextEventWithType:(RCTTextEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
text:(NSString *)text;
|
||||
|
||||
/**
|
||||
* Send scroll events
|
||||
* (You can send a fake scroll event by passing nil for scrollView)
|
||||
*/
|
||||
- (void)sendScrollEventWithType:(RCTScrollEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
scrollView:(UIScrollView *)scrollView
|
||||
userData:(NSDictionary *)userData;
|
||||
|
||||
@end
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTModuleIDs.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTEventDispatcher
|
||||
{
|
||||
RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)touchEvents
|
||||
{
|
||||
static NSArray *events;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
events = @[
|
||||
@"topTouchStart",
|
||||
@"topTouchMove",
|
||||
@"topTouchEnd",
|
||||
@"topTouchCancel",
|
||||
];
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
- (void)sendRawEventWithType:(NSString *)eventType body:(NSDictionary *)body
|
||||
{
|
||||
static NSSet *touchEvents;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
touchEvents = [NSSet setWithArray:[self touchEvents]];
|
||||
});
|
||||
|
||||
RCTAssert(![touchEvents containsObject:eventType], @"Touch events must be"
|
||||
"sent via the sendTouchEventWithOrderedTouches: method, not sendRawEventWithType:");
|
||||
|
||||
RCTAssert([body[@"target"] isKindOfClass:[NSNumber class]],
|
||||
@"Event body dictionary must include a 'target' property containing a react tag");
|
||||
|
||||
[_bridge enqueueJSCall:RCTModuleIDReactIOSEventEmitter
|
||||
methodID:RCTEventEmitterReceiveEvent
|
||||
args:@[body[@"target"], eventType, body]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs information about touch events to send across the serialized
|
||||
* boundary. This data should be compliant with W3C `Touch` objects. This data
|
||||
* alone isn't sufficient to construct W3C `Event` objects. To construct that,
|
||||
* there must be a simple receiver on the other side of the bridge that
|
||||
* organizes the touch objects into `Event`s.
|
||||
*
|
||||
* We send the data as an array of `Touch`es, the type of action
|
||||
* (start/end/move/cancel) and the indices that represent "changed" `Touch`es
|
||||
* from that array.
|
||||
*/
|
||||
- (void)sendTouchEventWithType:(RCTTouchEventType)type
|
||||
touches:(NSArray *)touches
|
||||
changedIndexes:(NSArray *)changedIndexes
|
||||
{
|
||||
RCTAssert(touches.count, @"No touches in touchEventArgsForOrderedTouches");
|
||||
|
||||
[_bridge enqueueJSCall:RCTModuleIDReactIOSEventEmitter
|
||||
methodID:RCTEventEmitterReceiveTouches
|
||||
args:@[[self touchEvents][type], touches, changedIndexes]];
|
||||
}
|
||||
|
||||
- (void)sendTextEventWithType:(RCTTextEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
text:(NSString *)text
|
||||
{
|
||||
static NSArray *events;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
events = @[
|
||||
@"topFocus",
|
||||
@"topBlur",
|
||||
@"topChange",
|
||||
@"topSubmitEditing",
|
||||
@"topEndEditing",
|
||||
];
|
||||
});
|
||||
|
||||
[self sendRawEventWithType:events[type] body:@{
|
||||
@"text": text,
|
||||
@"target": reactTag
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: throttling
|
||||
* NOTE: the old system used a per-scrollview throttling
|
||||
* which would be fairly easy to re-implement if needed,
|
||||
* but this is non-optimal as it leads to degradation in
|
||||
* scroll responsiveness. A better solution would be to
|
||||
* coalesce multiple scroll events into a single batch.
|
||||
*/
|
||||
- (void)sendScrollEventWithType:(RCTScrollEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
scrollView:(UIScrollView *)scrollView
|
||||
userData:(NSDictionary *)userData
|
||||
{
|
||||
static NSArray *events;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
events = @[
|
||||
@"topScrollBeginDrag",
|
||||
@"topScroll",
|
||||
@"topScrollEndDrag",
|
||||
@"topMomentumScrollBegin",
|
||||
@"topMomentumScrollEnd",
|
||||
@"topScrollAnimationEnd",
|
||||
];
|
||||
});
|
||||
|
||||
NSDictionary *body = @{
|
||||
@"contentOffset": @{
|
||||
@"x": @(scrollView.contentOffset.x),
|
||||
@"y": @(scrollView.contentOffset.y)
|
||||
},
|
||||
@"contentSize": @{
|
||||
@"width": @(scrollView.contentSize.width),
|
||||
@"height": @(scrollView.contentSize.height)
|
||||
},
|
||||
@"layoutMeasurement": @{
|
||||
@"width": @(scrollView.frame.size.width),
|
||||
@"height": @(scrollView.frame.size.height)
|
||||
},
|
||||
@"zoomScale": @(scrollView.zoomScale ?: 1),
|
||||
@"target": reactTag
|
||||
};
|
||||
|
||||
if (userData) {
|
||||
NSMutableDictionary *mutableBody = [body mutableCopy];
|
||||
[mutableBody addEntriesFromDictionary:userData];
|
||||
body = mutableBody;
|
||||
}
|
||||
|
||||
[self sendRawEventWithType:events[type] body:body];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,52 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTModuleIDs.h"
|
||||
|
||||
/**
|
||||
* Simple utility to help extract arguments to JS invocations of React event
|
||||
* emitter (IOS version).
|
||||
*/
|
||||
@interface RCTEventExtractor : NSObject
|
||||
|
||||
+ (NSArray *)eventArgs:(NSNumber *)tag type:(RCTEventType)type nativeEventObj:(NSDictionary *)nativeEventObj;
|
||||
|
||||
/**
|
||||
* Constructs information about touch events to send across the serialized
|
||||
* boundary. This data should be compliant with W3C `Touch` objects. This data
|
||||
* alone isn't sufficient to construct W3C `Event` objects. To construct that,
|
||||
* there must be a simple receiver on the other side of the bridge that
|
||||
* organizes the touch objects into `Event`s.
|
||||
*
|
||||
* We send the data as an array of `Touch`es, the type of action
|
||||
* (start/end/move/cancel) and the indices that represent "changed" `Touch`es
|
||||
* from that array.
|
||||
*/
|
||||
+ (NSArray *)touchEventArgsForOrderedTouches:(NSArray *)orderedTouches
|
||||
orderedStartTags:(NSArray *)orderedStartTags
|
||||
orderedTouchIDs:(NSArray *)orderedTouchIDs
|
||||
changedIndices:(NSArray *)changedIndices
|
||||
type:(RCTEventType)type
|
||||
view:(UIView *)view;
|
||||
|
||||
+ (NSDictionary *)scrollEventObject:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
|
||||
/**
|
||||
* Useful when having to simply communicate the fact that *something* scrolled.
|
||||
* When JavaScript infers gestures based on the event stream, any type of
|
||||
* scroll that occurs in the native platform will cause ongoing gestures to
|
||||
* cancel. Scroll/table views already send scroll events appropriately, but
|
||||
* this method is useful for other views that don't actually scroll, but should
|
||||
* interrupt JavaScript gestures as scrolls do.
|
||||
*/
|
||||
+ (NSDictionary *)fakeScrollEventObjectFor:(NSNumber *)reactTag;
|
||||
|
||||
/**
|
||||
* Finds the React target of a touch. This must be done when the touch starts,
|
||||
* else `UIKit` gesture recognizers may destroy the touch's target.
|
||||
*/
|
||||
+ (NSNumber *)touchStartTarget:(UITouch *)touch inView:(UIView *)view;
|
||||
|
||||
@end
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTEventExtractor.h"
|
||||
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTViewNodeProtocol.h"
|
||||
|
||||
@implementation RCTEventExtractor
|
||||
|
||||
// TODO (#5906496): an array lookup would be better than a switch statement here
|
||||
|
||||
/**
|
||||
* Keep in sync with `IOSEventConstants.js`.
|
||||
* TODO (#5906496): do this sync programmatically instead of manually
|
||||
*/
|
||||
+ (NSString *)topLevelTypeForEventType:(RCTEventType)eventType
|
||||
{
|
||||
switch(eventType) {
|
||||
case RCTEventTap:
|
||||
return @"topTap";
|
||||
case RCTEventVisibleCellsChange:
|
||||
return @"topVisibleCellsChange";
|
||||
case RCTEventNavigateBack:
|
||||
return @"topNavigateBack";
|
||||
case RCTEventNavRightButtonTap:
|
||||
return @"topNavRightButtonTap";
|
||||
case RCTEventChange:
|
||||
return @"topChange";
|
||||
case RCTEventTextFieldDidFocus:
|
||||
return @"topFocus";
|
||||
case RCTEventTextFieldWillBlur:
|
||||
return @"topBlur";
|
||||
case RCTEventTextFieldSubmitEditing:
|
||||
return @"topSubmitEditing";
|
||||
case RCTEventTextFieldEndEditing:
|
||||
return @"topEndEditing";
|
||||
case RCTEventTextInput:
|
||||
return @"topTextInput";
|
||||
case RCTEventLongPress:
|
||||
return @"topLongPress"; // Not yet supported
|
||||
case RCTEventTouchCancel:
|
||||
return @"topTouchCancel";
|
||||
case RCTEventTouchEnd:
|
||||
return @"topTouchEnd";
|
||||
case RCTEventTouchMove:
|
||||
return @"topTouchMove";
|
||||
case RCTEventTouchStart:
|
||||
return @"topTouchStart";
|
||||
case RCTEventScrollBeginDrag:
|
||||
return @"topScrollBeginDrag";
|
||||
case RCTEventScroll:
|
||||
return @"topScroll";
|
||||
case RCTEventScrollEndDrag:
|
||||
return @"topScrollEndDrag";
|
||||
case RCTEventScrollAnimationEnd:
|
||||
return @"topScrollAnimationEnd";
|
||||
case RCTEventSelectionChange:
|
||||
return @"topSelectionChange";
|
||||
case RCTEventMomentumScrollBegin:
|
||||
return @"topMomentumScrollBegin";
|
||||
case RCTEventMomentumScrollEnd:
|
||||
return @"topMomentumScrollEnd";
|
||||
case RCTEventPullToRefresh:
|
||||
return @"topPullToRefresh";
|
||||
case RCTEventLoadingStart:
|
||||
return @"topLoadingStart";
|
||||
case RCTEventLoadingFinish:
|
||||
return @"topLoadingFinish";
|
||||
case RCTEventLoadingError:
|
||||
return @"topLoadingError";
|
||||
case RCTEventNavigationProgress:
|
||||
return @"topNavigationProgress";
|
||||
default :
|
||||
RCTLogError(@"Unrecognized event type: %tu", eventType);
|
||||
return @"unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO (#5906496): Cache created string messages for each event type/tag target (for
|
||||
* events that have no data) to save allocations.
|
||||
*/
|
||||
+ (NSArray *)eventArgs:(NSNumber *)reactTag
|
||||
type:(RCTEventType)type
|
||||
nativeEventObj:(NSDictionary *)nativeEventObj
|
||||
{
|
||||
NSString *topLevelType = [RCTEventExtractor topLevelTypeForEventType:type];
|
||||
return @[reactTag ?: @0, topLevelType, nativeEventObj];
|
||||
}
|
||||
|
||||
+ (NSArray *)touchEventArgsForOrderedTouches:(NSArray *)orderedTouches
|
||||
orderedStartTags:(NSArray *)orderedStartTags
|
||||
orderedTouchIDs:(NSArray *)orderedTouchIDs
|
||||
changedIndices:(NSArray *)changedIndices
|
||||
type:(RCTEventType)type
|
||||
view:(UIView *)view
|
||||
{
|
||||
if (!orderedTouches || !orderedTouches.count) {
|
||||
RCTLogError(@"No touches in touchEventArgsForOrderedTouches");
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray *touchObjects = [[NSMutableArray alloc] init];
|
||||
for (NSInteger i = 0; i < orderedTouches.count; i++) {
|
||||
NSDictionary *touchObj =
|
||||
[RCTEventExtractor touchObj:orderedTouches[i]
|
||||
withTargetTag:orderedStartTags[i]
|
||||
withTouchID:orderedTouchIDs[i]
|
||||
inView:view];
|
||||
[touchObjects addObject:touchObj];
|
||||
}
|
||||
NSString *topLevelType = [RCTEventExtractor topLevelTypeForEventType:type];
|
||||
return @[topLevelType, touchObjects, changedIndices];
|
||||
}
|
||||
|
||||
+ (NSNumber *)touchStartTarget:(UITouch *)touch inView:(UIView *)view
|
||||
{
|
||||
UIView <RCTViewNodeProtocol> *closestReactAncestor = [RCTUIManager closestReactAncestorThatRespondsToTouch:touch];
|
||||
return [closestReactAncestor reactTag];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an object that contains all of the important touch data. This
|
||||
* should contain a superset of a W3C `Touch` object. The `Event` objects that
|
||||
* reference these touches can only be constructed from a collection of touch
|
||||
* objects that are recieved across the serialized bridge.
|
||||
*
|
||||
* Must accept the `targetReactTag` because targets are reset to `nil` by
|
||||
* `UIKit` gesture system. We had to pre-recorded at the time of touch start.
|
||||
*/
|
||||
+ (NSDictionary *)touchObj:(UITouch *)touch
|
||||
withTargetTag:(NSNumber *)targetReactTag
|
||||
withTouchID:(NSNumber *)touchID
|
||||
inView:(UIView *)view
|
||||
{
|
||||
CGPoint location = [touch locationInView:view];
|
||||
CGPoint locInView = [touch locationInView:touch.view];
|
||||
double timeStamp = touch.timestamp * 1000.0; // convert to ms
|
||||
return @{
|
||||
@"pageX": @(location.x),
|
||||
@"pageY": @(location.y),
|
||||
@"locationX": @(locInView.x),
|
||||
@"locationY": @(locInView.y),
|
||||
@"target": targetReactTag,
|
||||
@"identifier": touchID,
|
||||
@"timeStamp": @(timeStamp),
|
||||
@"touches": [NSNull null], // We hijack this touchObj to serve both as an event
|
||||
@"changedTouches": [NSNull null], // and as a Touch object, so making this JIT friendly.
|
||||
};
|
||||
}
|
||||
|
||||
// TODO (#5906496): shouldn't some of these strings be constants?
|
||||
|
||||
+ (NSDictionary *)makeScrollEventObject:(UIScrollView *)uiScrollView reactTag:(NSNumber *)reactTag;
|
||||
{
|
||||
return @{
|
||||
@"contentOffset": @{
|
||||
@"x": @(uiScrollView.contentOffset.x),
|
||||
@"y": @(uiScrollView.contentOffset.y)
|
||||
},
|
||||
@"contentSize": @{
|
||||
@"width": @(uiScrollView.contentSize.width),
|
||||
@"height": @(uiScrollView.contentSize.height)
|
||||
},
|
||||
@"layoutMeasurement": @{
|
||||
@"width": @(uiScrollView.frame.size.width),
|
||||
@"height": @(uiScrollView.frame.size.height)
|
||||
},
|
||||
@"zoomScale": @(uiScrollView.zoomScale),
|
||||
@"target": reactTag,
|
||||
};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)scrollEventObject:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
return [RCTEventExtractor makeScrollEventObject:scrollView reactTag:reactTag];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)fakeScrollEventObjectFor:(NSNumber *)reactTag
|
||||
{
|
||||
return @{
|
||||
@"contentOffset": @{
|
||||
@"x": @0,
|
||||
@"y": @0
|
||||
},
|
||||
@"contentSize": @{
|
||||
@"width": @0,
|
||||
@"height": @0
|
||||
},
|
||||
@"layoutMeasurement": @{
|
||||
@"width": @0,
|
||||
@"height": @0
|
||||
},
|
||||
@"zoomScale": @1,
|
||||
@"target": reactTag
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *viewRegistry);
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTShadowView;
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
@ -79,7 +79,7 @@ _RCTExportSectionName))) static const RCTExportEntry __rct_export_entry__ = { __
|
|||
/**
|
||||
* This method instantiates a native view to be managed by the module.
|
||||
*/
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
@optional
|
||||
|
||||
|
@ -172,4 +172,4 @@ RCT_REMAP_VIEW_PROPERTY(name, name)
|
|||
*/
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(RCTSparseArray *)shadowViewRegistry;
|
||||
|
||||
@end
|
||||
@end
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
@interface RCTJavaScriptEventDispatcher : NSObject
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge;
|
||||
- (void)sendDeviceEventWithArgs:(NSArray *)args;
|
||||
- (void)sendEventWithArgs:(NSArray *)args;
|
||||
- (void)sendTouchesWithArgs:(NSArray *)args;
|
||||
|
||||
@end
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTModuleIDs.h"
|
||||
|
||||
@implementation RCTJavaScriptEventDispatcher
|
||||
{
|
||||
RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_bridge = bridge;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)sendDeviceEventWithArgs:(NSArray *)args
|
||||
{
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
[_bridge enqueueJSCall:RCTModuleIDDeviceEventEmitter
|
||||
methodID:RCTDeviceEventEmitterEmit
|
||||
args:args];
|
||||
}
|
||||
|
||||
- (void)sendEventWithArgs:(NSArray *)args
|
||||
{
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
[_bridge enqueueJSCall:RCTModuleIDReactIOSEventEmitter
|
||||
methodID:RCTEventEmitterReceiveEvent
|
||||
args:args];
|
||||
}
|
||||
|
||||
- (void)sendTouchesWithArgs:(NSArray *)args
|
||||
{
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
[_bridge enqueueJSCall:RCTModuleIDReactIOSEventEmitter
|
||||
methodID:RCTEventEmitterReceiveTouches
|
||||
args:args];
|
||||
}
|
||||
|
||||
@end
|
|
@ -14,7 +14,6 @@ typedef NS_ENUM(NSUInteger, RCTJSModuleIDs) {
|
|||
RCTModuleIDDimensions,
|
||||
RCTModuleIDDeviceEventEmitter,
|
||||
RCTModuleIDNativeAppEventEmitter,
|
||||
RCTModuleIDRenderingPerf,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -25,39 +24,6 @@ typedef NS_ENUM(NSUInteger, RCTEventEmitterRemoteMethodIDs) {
|
|||
RCTEventEmitterReceiveTouches
|
||||
};
|
||||
|
||||
/**
|
||||
* `RCTEventEmitter`: Encoding of parameters.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, RCTEventType) {
|
||||
RCTEventTap = 1,
|
||||
RCTEventVisibleCellsChange,
|
||||
RCTEventNavigateBack,
|
||||
RCTEventNavRightButtonTap,
|
||||
RCTEventChange,
|
||||
RCTEventTextFieldDidFocus,
|
||||
RCTEventTextFieldWillBlur,
|
||||
RCTEventTextFieldSubmitEditing,
|
||||
RCTEventTextFieldEndEditing,
|
||||
RCTEventTextInput,
|
||||
RCTEventLongPress,
|
||||
RCTEventTouchStart,
|
||||
RCTEventTouchMove,
|
||||
RCTEventTouchCancel,
|
||||
RCTEventTouchEnd,
|
||||
RCTEventScrollBeginDrag,
|
||||
RCTEventScroll,
|
||||
RCTEventScrollEndDrag,
|
||||
RCTEventSelectionChange,
|
||||
RCTEventMomentumScrollBegin,
|
||||
RCTEventMomentumScrollEnd,
|
||||
RCTEventPullToRefresh,
|
||||
RCTEventScrollAnimationEnd,
|
||||
RCTEventLoadingStart,
|
||||
RCTEventLoadingFinish,
|
||||
RCTEventLoadingError,
|
||||
RCTEventNavigationProgress,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, RCTKeyCode) {
|
||||
RCTKeyCodeBackspace = 8,
|
||||
RCTKeyCodeReturn = 13,
|
||||
|
@ -82,18 +48,10 @@ typedef NS_ENUM(NSUInteger, RCTDimensionsMethodIDs) {
|
|||
RCTDimensionsSet = 0
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, RCTRenderingPerfMethodIDs) {
|
||||
RCTRenderingPerfToggle = 0,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, RCTDeviceEventEmitterMethodIDs) {
|
||||
RCTDeviceEventEmitterEmit = 0
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, RCTNativeAppEventEmitterMethodIDs) {
|
||||
RCTNativeAppEventEmitterEmit = 0
|
||||
};
|
||||
|
||||
@interface RCTModuleIDs : NSObject
|
||||
|
||||
+ (NSDictionary *)config;
|
||||
|
|
|
@ -21,16 +21,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
@"RCTRenderingPerf": @{
|
||||
@"moduleID": @(RCTModuleIDRenderingPerf),
|
||||
@"methods": @{
|
||||
@"toggle": @{
|
||||
@"methodID": @(RCTRenderingPerfToggle),
|
||||
@"type": @"local"
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@"RCTDeviceEventEmitter": @{
|
||||
@"moduleID": @(RCTModuleIDDeviceEventEmitter),
|
||||
@"methods": @{
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
// Copyright 2013-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTMultiTouchGestureRecognizer;
|
||||
|
||||
@protocol RCTMultiTouchGestureRecognizerListener <NSObject>
|
||||
|
||||
- (void)handleTouchesStarted:(NSSet *)startedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event;
|
||||
|
||||
- (void)handleTouchesMoved:(NSSet *)movedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event;
|
||||
|
||||
- (void)handleTouchesEnded:(NSSet *)endedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event;
|
||||
|
||||
- (void)handleTouchesCancelled:(NSSet *)cancelledTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTMultiTouchGestureRecognizer : UIGestureRecognizer
|
||||
|
||||
@property (nonatomic, weak) id<RCTMultiTouchGestureRecognizerListener> touchEventDelegate;
|
||||
|
||||
@end
|
|
@ -1,103 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
// Copyright 2013-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTMultiTouchGestureRecognizer.h"
|
||||
|
||||
#import <UIKit/UIGestureRecognizerSubclass.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
|
||||
@implementation RCTMultiTouchGestureRecognizer
|
||||
|
||||
- (void)touchesBegan:(NSSet *)startedTouches withEvent:(UIEvent *)event {
|
||||
[super touchesBegan:startedTouches withEvent:event];
|
||||
if (!self.touchEventDelegate) {
|
||||
RCTLogError(@"No Touch Delegate for Simple Gesture Recognizer");
|
||||
return;
|
||||
}
|
||||
self.state = UIGestureRecognizerStateBegan;
|
||||
[self.touchEventDelegate handleTouchesStarted:startedTouches
|
||||
forMultiGestureRecognizer:self
|
||||
withEvent:event];
|
||||
}
|
||||
|
||||
- (void)touchesMoved:(NSSet *)movedTouches withEvent:(UIEvent *)event {
|
||||
[super touchesMoved:movedTouches withEvent:event];
|
||||
if (self.state == UIGestureRecognizerStateFailed) {
|
||||
return;
|
||||
}
|
||||
[self.touchEventDelegate handleTouchesMoved:movedTouches
|
||||
forMultiGestureRecognizer:self
|
||||
withEvent:event];
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet *)endedTouches withEvent:(UIEvent *)event {
|
||||
[super touchesEnded:endedTouches withEvent:event];
|
||||
[self.touchEventDelegate handleTouchesEnded:endedTouches
|
||||
forMultiGestureRecognizer:self
|
||||
withEvent:event];
|
||||
// These may be a different set than the total set of touches.
|
||||
NSSet *touches = [event touchesForGestureRecognizer:self];
|
||||
|
||||
BOOL hasEnded = [self _allTouchesAreCanceledOrEnded:touches];
|
||||
|
||||
if (hasEnded) {
|
||||
self.state = UIGestureRecognizerStateEnded;
|
||||
} else if ([self _anyTouchesChanged:touches]) {
|
||||
self.state = UIGestureRecognizerStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet *)cancelledTouches withEvent:(UIEvent *)event {
|
||||
[super touchesCancelled:cancelledTouches withEvent:event];
|
||||
[self.touchEventDelegate handleTouchesCancelled:cancelledTouches
|
||||
forMultiGestureRecognizer:self
|
||||
withEvent:event];
|
||||
// These may be a different set than the total set of touches.
|
||||
NSSet *touches = [event touchesForGestureRecognizer:self];
|
||||
|
||||
BOOL hasCanceled = [self _allTouchesAreCanceledOrEnded:touches];
|
||||
|
||||
if (hasCanceled) {
|
||||
self.state = UIGestureRecognizerStateFailed;
|
||||
} else if ([self _anyTouchesChanged:touches]) {
|
||||
self.state = UIGestureRecognizerStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (BOOL)_allTouchesAreCanceledOrEnded:(NSSet *)touches
|
||||
{
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
|
||||
return NO;
|
||||
} else if (touch.phase == UITouchPhaseStationary) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_anyTouchesChanged:(NSSet *)touches
|
||||
{
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
|
@ -4,12 +4,9 @@
|
|||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTContextExecutor.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTJavaScriptAppEngine.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTModuleIDs.h"
|
||||
#import "RCTRedBox.h"
|
||||
#import "RCTShadowView.h"
|
||||
#import "RCTSparseArray.h"
|
||||
#import "RCTTouchHandler.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTUtils.h"
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
|
||||
/**
|
||||
* Handles throttling of scroll events that are dispatched to JavaScript.
|
||||
*/
|
||||
@interface RCTScrollDispatcher : NSObject
|
||||
|
||||
@property (nonatomic, readwrite, assign) NSInteger throttleScrollCallbackMS;
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTJavaScriptEventDispatcher *)dispatcher;
|
||||
|
||||
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag;
|
||||
|
||||
@end
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTScrollDispatcher.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTScrollDispatcher
|
||||
{
|
||||
RCTJavaScriptEventDispatcher *_eventDispatcher;
|
||||
NSTimeInterval _lastScrollDispatchTime;
|
||||
BOOL _allowNextScrollNoMatterWhat;
|
||||
NSMutableDictionary *_cachedChildFrames;
|
||||
CGPoint _lastContentOffset;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTJavaScriptEventDispatcher *)dispatcher
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_eventDispatcher = dispatcher;
|
||||
_throttleScrollCallbackMS = 0;
|
||||
_lastScrollDispatchTime = CACurrentMediaTime();
|
||||
_cachedChildFrames = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)_getUpdatedChildFrames:(UIScrollView *)scrollView forUpdateKey:(NSString *)updateKey
|
||||
{
|
||||
NSArray *children = [scrollView.subviews[0] reactSubviews];
|
||||
NSMutableArray *updatedChildFrames = [NSMutableArray new];
|
||||
NSMutableArray *cachedFrames = _cachedChildFrames[updateKey];
|
||||
if (!cachedFrames) {
|
||||
cachedFrames = [[NSMutableArray alloc] initWithCapacity:children.count];
|
||||
_cachedChildFrames[updateKey] = cachedFrames;
|
||||
}
|
||||
for (int ii = 0; ii < children.count; ii++) {
|
||||
CGRect newFrame = [children[ii] frame];
|
||||
if (cachedFrames.count <= ii || !CGRectEqualToRect(newFrame, [cachedFrames[ii] CGRectValue])) {
|
||||
[updatedChildFrames addObject:
|
||||
@{
|
||||
@"index": @(ii),
|
||||
@"x": @(newFrame.origin.x),
|
||||
@"y": @(newFrame.origin.y),
|
||||
@"width": @(newFrame.size.width),
|
||||
@"height": @(newFrame.size.height),
|
||||
}];
|
||||
NSValue *frameObj = [NSValue valueWithCGRect:newFrame];
|
||||
if (cachedFrames.count <= ii) {
|
||||
[cachedFrames addObject:frameObj];
|
||||
} else {
|
||||
cachedFrames[ii] = frameObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return updatedChildFrames;
|
||||
}
|
||||
|
||||
- (void)_dispatchScroll:(UIScrollView *)scrollView forUpdateKey:(NSString *)updateKey reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
NSTimeInterval now = CACurrentMediaTime();
|
||||
NSTimeInterval dt = now - _lastScrollDispatchTime;
|
||||
NSMutableDictionary *mutableNativeObj = [[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag] mutableCopy];
|
||||
if (updateKey) {
|
||||
NSArray *updatedChildFrames = [self _getUpdatedChildFrames:scrollView forUpdateKey:updateKey];
|
||||
if (updatedChildFrames.count > 0) {
|
||||
mutableNativeObj[@"updatedChildFrames"] = updatedChildFrames;
|
||||
}
|
||||
}
|
||||
mutableNativeObj[@"velocity"] = @{
|
||||
@"x": @((scrollView.contentOffset.x - _lastContentOffset.x) / dt),
|
||||
@"y": @((scrollView.contentOffset.y - _lastContentOffset.y) / dt),
|
||||
};
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventScroll
|
||||
nativeEventObj:mutableNativeObj]];
|
||||
_lastScrollDispatchTime = now;
|
||||
_lastContentOffset = scrollView.contentOffset;
|
||||
_allowNextScrollNoMatterWhat = NO;
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventScrollAnimationEnd
|
||||
nativeEventObj:[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag]]];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
NSTimeInterval now = CACurrentMediaTime();
|
||||
NSTimeInterval throttleScrollCallbackSeconds = _throttleScrollCallbackMS / 1000.0f;
|
||||
if (_allowNextScrollNoMatterWhat ||
|
||||
(_throttleScrollCallbackMS != 0 && throttleScrollCallbackSeconds < (now - _lastScrollDispatchTime))) {
|
||||
[self _dispatchScroll:scrollView forUpdateKey:@"didScroll" reactTag:reactTag];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventMomentumScrollBegin
|
||||
nativeEventObj:[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag]]];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventMomentumScrollEnd
|
||||
nativeEventObj:[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag]]];
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
_allowNextScrollNoMatterWhat = YES;
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventScrollBeginDrag
|
||||
nativeEventObj:[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag]]];
|
||||
}
|
||||
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView reactTag:(NSNumber *)reactTag
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:reactTag
|
||||
type:RCTEventScrollEndDrag
|
||||
nativeEventObj:[RCTEventExtractor scrollEventObject:scrollView reactTag:reactTag]]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
|
@ -14,19 +14,17 @@
|
|||
|
||||
- (instancetype)initWithCapacity:(NSUInteger)capacity
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_storage = [NSMutableDictionary dictionaryWithCapacity:capacity];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSparseArray:(RCTSparseArray *)sparseArray
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_storage = [sparseArray->_storage copy];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,31 +2,11 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTTouchHandler : NSObject
|
||||
@interface RCTTouchHandler : UIGestureRecognizer
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
rootView:(UIView *)rootView;
|
||||
|
||||
@property (nonatomic, readwrite, strong) RCTJavaScriptEventDispatcher *eventDispatcher;
|
||||
|
||||
/**
|
||||
* Maintaining the set of active touches by the time they started touching.
|
||||
*/
|
||||
@property (nonatomic, readonly, strong) NSMutableArray *orderedTouches;
|
||||
|
||||
/**
|
||||
* Array managed in parallel to `orderedTouches` tracking original `reactTag`
|
||||
* for each touch. This must be kept track of because `UIKit` destroys the
|
||||
* touch targets if touches are canceled and we have no other way to recover
|
||||
* this information.
|
||||
*/
|
||||
@property (nonatomic, readonly, strong) NSMutableArray *orderedTouchStartTags;
|
||||
|
||||
/**
|
||||
* IDs that uniquely represent a touch among all of the active touches.
|
||||
*/
|
||||
@property (nonatomic, readonly, strong) NSMutableArray *orderedTouchIDs;
|
||||
|
||||
@end
|
||||
|
|
|
@ -2,23 +2,29 @@
|
|||
|
||||
#import "RCTTouchHandler.h"
|
||||
|
||||
#import <UIKit/UIGestureRecognizerSubclass.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTMultiTouchGestureRecognizer.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@interface RCTTouchHandler () <RCTMultiTouchGestureRecognizerListener, UIGestureRecognizerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTTouchHandler
|
||||
{
|
||||
UIView *_rootView;
|
||||
NSMutableArray *_gestureRecognizers;
|
||||
__weak UIView *_rootView;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
|
||||
/**
|
||||
* Arrays managed in parallel tracking native touch object along with the
|
||||
* native view that was touched, and the react touch data dictionary.
|
||||
* This must be kept track of because `UIKit` destroys the touch targets
|
||||
* if touches are canceled and we have no other way to recover this information.
|
||||
*/
|
||||
NSMutableOrderedSet *_nativeTouches;
|
||||
NSMutableArray *_reactTouches;
|
||||
NSMutableArray *_touchViews;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
|
@ -26,113 +32,60 @@
|
|||
RCT_NOT_DESIGNATED_INITIALIZER();
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithTarget:(id)target action:(SEL)action
|
||||
{
|
||||
RCT_NOT_DESIGNATED_INITIALIZER();
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
rootView:(UIView *)rootView
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super initWithTarget:nil action:NULL])) {
|
||||
|
||||
RCTAssert(eventDispatcher != nil, @"Expect an event dispatcher");
|
||||
RCTAssert(rootView != nil, @"Expect a root view");
|
||||
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_rootView = rootView;
|
||||
_gestureRecognizers = [NSMutableArray new];
|
||||
_orderedTouches = [[NSMutableArray alloc] init];
|
||||
_orderedTouchStartTags = [[NSMutableArray alloc] init];
|
||||
_orderedTouchIDs = [[NSMutableArray alloc] init];
|
||||
[self _loadGestureRecognizers];
|
||||
|
||||
_nativeTouches = [[NSMutableOrderedSet alloc] init];
|
||||
_reactTouches = [[NSMutableArray alloc] init];
|
||||
_touchViews = [[NSMutableArray alloc] init];
|
||||
|
||||
// `cancelsTouchesInView` is needed in order to be used as a top level event delegated recognizer. Otherwise, lower
|
||||
// level components not build using RCT, will fail to recognize gestures.
|
||||
self.cancelsTouchesInView = NO;
|
||||
[_rootView addGestureRecognizer:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self removeGestureRecognizers];
|
||||
}
|
||||
|
||||
#pragma mark - Gesture Recognizers
|
||||
|
||||
- (void)_loadGestureRecognizers
|
||||
{
|
||||
[self _addRecognizerForEvent:RCTEventTap];
|
||||
[self _addRecognizerForEvent:RCTEventLongPress];
|
||||
[self _addRecognizerForSimpleTouchEvents];
|
||||
}
|
||||
|
||||
- (void)_addRecognizerForSimpleTouchEvents
|
||||
{
|
||||
RCTMultiTouchGestureRecognizer *multiTouchRecognizer =
|
||||
[[RCTMultiTouchGestureRecognizer alloc] initWithTarget:self action:@selector(handleMultiTouchGesture:)];
|
||||
multiTouchRecognizer.touchEventDelegate = self;
|
||||
[self _addRecognizer:multiTouchRecognizer];
|
||||
}
|
||||
|
||||
- (void)_addRecognizerForEvent:(RCTEventType)event
|
||||
{
|
||||
UIGestureRecognizer *recognizer = nil;
|
||||
switch (event) {
|
||||
case RCTEventTap:
|
||||
recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
|
||||
((UITapGestureRecognizer *)recognizer).numberOfTapsRequired = 1;
|
||||
break;
|
||||
|
||||
case RCTEventVisibleCellsChange:
|
||||
case RCTEventNavigateBack:
|
||||
case RCTEventNavRightButtonTap:
|
||||
case RCTEventChange:
|
||||
case RCTEventTextFieldDidFocus:
|
||||
case RCTEventTextFieldWillBlur:
|
||||
case RCTEventTextFieldSubmitEditing:
|
||||
case RCTEventTextFieldEndEditing:
|
||||
case RCTEventScroll:
|
||||
break;
|
||||
|
||||
case RCTEventLongPress:
|
||||
recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
break;
|
||||
default:
|
||||
RCTLogError(@"Unrecognized event type for gesture: %zd", event);
|
||||
|
||||
}
|
||||
[self _addRecognizer:recognizer];
|
||||
}
|
||||
|
||||
- (void)_addRecognizer:(UIGestureRecognizer *)recognizer
|
||||
{
|
||||
// `cancelsTouchesInView` is needed in order to be used as a top level event delegated recognizer. Otherwise, lower
|
||||
// level components not build using RCT, will fail to recognize gestures.
|
||||
recognizer.cancelsTouchesInView = NO;
|
||||
recognizer.delegate = self;
|
||||
[_gestureRecognizers addObject:recognizer];
|
||||
[_rootView addGestureRecognizer:recognizer];
|
||||
}
|
||||
|
||||
- (void)removeGestureRecognizers
|
||||
{
|
||||
for (UIGestureRecognizer *recognizer in _gestureRecognizers) {
|
||||
[recognizer setDelegate:nil];
|
||||
[recognizer removeTarget:nil action:NULL];
|
||||
[_rootView removeGestureRecognizer:recognizer];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Bookkeeping for touch indices
|
||||
|
||||
- (void)_recordNewTouches:(NSSet *)touches
|
||||
{
|
||||
for (UITouch *touch in touches) {
|
||||
NSUInteger currentIndex = [_orderedTouches indexOfObject:touch];
|
||||
if (currentIndex != NSNotFound) {
|
||||
RCTLogError(@"Touch is already recorded. This is a critical bug.");
|
||||
[_orderedTouches removeObjectAtIndex:currentIndex];
|
||||
[_orderedTouchStartTags removeObjectAtIndex:currentIndex];
|
||||
[_orderedTouchIDs removeObjectAtIndex:currentIndex];
|
||||
|
||||
RCTAssert(![_nativeTouches containsObject:touch],
|
||||
@"Touch is already recorded. This is a critical bug.");
|
||||
|
||||
// Find closest React-managed touchable view
|
||||
UIView *targetView = touch.view;
|
||||
while (targetView) {
|
||||
if (targetView.reactTag && targetView.userInteractionEnabled) { // TODO: implement respondsToTouch: mechanism
|
||||
break;
|
||||
}
|
||||
targetView = targetView.superview;
|
||||
}
|
||||
NSNumber *touchStartTag = [RCTEventExtractor touchStartTarget:touch inView:_rootView];
|
||||
|
||||
|
||||
RCTAssert(targetView.reactTag && targetView.userInteractionEnabled,
|
||||
@"No react view found for touch - something went wrong.");
|
||||
|
||||
// Get new, unique touch id
|
||||
const NSUInteger RCTMaxTouches = 11; // This is the maximum supported by iDevices
|
||||
NSInteger touchID = ([_orderedTouchIDs.lastObject integerValue] + 1) % RCTMaxTouches;
|
||||
for (NSNumber *n in _orderedTouchIDs) {
|
||||
NSInteger usedID = [n integerValue];
|
||||
NSInteger touchID = ([_reactTouches.lastObject[@"target"] integerValue] + 1) % RCTMaxTouches;
|
||||
for (NSDictionary *reactTouch in _reactTouches) {
|
||||
NSInteger usedID = [reactTouch[@"target"] integerValue];
|
||||
if (usedID == touchID) {
|
||||
// ID has already been used, try next value
|
||||
touchID ++;
|
||||
|
@ -141,156 +94,117 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[_orderedTouches addObject:touch];
|
||||
[_orderedTouchStartTags addObject:touchStartTag];
|
||||
[_orderedTouchIDs addObject:@(touchID)];
|
||||
|
||||
// Create touch
|
||||
NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:9];
|
||||
reactTouch[@"target"] = targetView.reactTag;
|
||||
reactTouch[@"identifier"] = @(touchID);
|
||||
reactTouch[@"touches"] = [NSNull null]; // We hijack this touchObj to serve both as an event
|
||||
reactTouch[@"changedTouches"] = [NSNull null]; // and as a Touch object, so making this JIT friendly.
|
||||
|
||||
// Add to arrays
|
||||
[_touchViews addObject:targetView];
|
||||
[_nativeTouches addObject:touch];
|
||||
[_reactTouches addObject:reactTouch];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_recordRemovedTouches:(NSSet *)touches
|
||||
{
|
||||
for (UITouch *touch in touches) {
|
||||
NSUInteger currentIndex = [_orderedTouches indexOfObject:touch];
|
||||
if (currentIndex == NSNotFound) {
|
||||
RCTLogError(@"Touch is already removed. This is a critical bug.");
|
||||
} else {
|
||||
[_orderedTouches removeObjectAtIndex:currentIndex];
|
||||
[_orderedTouchStartTags removeObjectAtIndex:currentIndex];
|
||||
[_orderedTouchIDs removeObjectAtIndex:currentIndex];
|
||||
}
|
||||
NSUInteger index = [_nativeTouches indexOfObject:touch];
|
||||
RCTAssert(index != NSNotFound, @"Touch is already removed. This is a critical bug.");
|
||||
[_touchViews removeObjectAtIndex:index];
|
||||
[_nativeTouches removeObjectAtIndex:index];
|
||||
[_reactTouches removeObjectAtIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateReactTouchAtIndex:(NSInteger)touchIndex
|
||||
{
|
||||
UITouch *nativeTouch = _nativeTouches[touchIndex];
|
||||
CGPoint windowLocation = [nativeTouch locationInView:nativeTouch.window];
|
||||
CGPoint rootViewLocation = [nativeTouch.window convertPoint:windowLocation toView:_rootView];
|
||||
|
||||
UIView *touchView = _touchViews[touchIndex];
|
||||
CGPoint touchViewLocation = [nativeTouch.window convertPoint:windowLocation toView:touchView];
|
||||
|
||||
NSMutableDictionary *reactTouch = _reactTouches[touchIndex];
|
||||
reactTouch[@"pageX"] = @(rootViewLocation.x);
|
||||
reactTouch[@"pageY"] = @(rootViewLocation.y);
|
||||
reactTouch[@"locationX"] = @(touchViewLocation.x);
|
||||
reactTouch[@"locationY"] = @(touchViewLocation.y);
|
||||
reactTouch[@"timestamp"] = @(nativeTouch.timestamp * 1000); // in ms, for JS
|
||||
}
|
||||
|
||||
- (void)_updateAndDispatchTouches:(NSSet *)touches eventType:(RCTTouchEventType)eventType
|
||||
{
|
||||
// Update touches
|
||||
NSMutableArray *changedIndices = [[NSMutableArray alloc] init];
|
||||
for (UITouch *touch in touches) {
|
||||
NSInteger index = [_nativeTouches indexOfObject:touch];
|
||||
RCTAssert(index != NSNotFound, @"Touch not found. This is a critical bug.");
|
||||
[self _updateReactTouchAtIndex:index];
|
||||
[changedIndices addObject:@(index)];
|
||||
}
|
||||
|
||||
// Deep copy the touches because they will be accessed from another thread
|
||||
// TODO: would it be safer to do this in the bridge or executor, rather than trusting caller?
|
||||
NSMutableArray *reactTouches = [[NSMutableArray alloc] initWithCapacity:_reactTouches.count];
|
||||
for (NSDictionary *touch in _reactTouches) {
|
||||
[reactTouches addObject:[touch copy]];
|
||||
}
|
||||
|
||||
// Dispatch touch event
|
||||
[_eventDispatcher sendTouchEventWithType:eventType
|
||||
touches:reactTouches
|
||||
changedIndexes:changedIndices];
|
||||
}
|
||||
|
||||
#pragma mark - Gesture Recognizer Delegate Callbacks
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray *)_indicesOfTouches:(NSSet *)touchSet inArray:(NSArray *)array
|
||||
{
|
||||
NSMutableArray *result = [[NSMutableArray alloc] init];
|
||||
for (UITouch *touch in touchSet) {
|
||||
[result addObject:@([array indexOfObject:touch])];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)handleTouchesStarted:(NSSet *)startedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
self.state = UIGestureRecognizerStateBegan;
|
||||
|
||||
// "start" has to record new touches before extracting the event.
|
||||
// "end"/"cancel" needs to remove the touch *after* extracting the event.
|
||||
[self _recordNewTouches:startedTouches];
|
||||
NSArray *indicesOfStarts = [self _indicesOfTouches:startedTouches inArray:_orderedTouches];
|
||||
NSArray *args =
|
||||
[RCTEventExtractor touchEventArgsForOrderedTouches:_orderedTouches
|
||||
orderedStartTags:_orderedTouchStartTags
|
||||
orderedTouchIDs:_orderedTouchIDs
|
||||
changedIndices:indicesOfStarts
|
||||
type:RCTEventTouchStart
|
||||
view:_rootView];
|
||||
[_eventDispatcher sendTouchesWithArgs:args];
|
||||
[self _recordNewTouches:touches];
|
||||
[self _updateAndDispatchTouches:touches eventType:RCTTouchEventTypeStart];
|
||||
}
|
||||
|
||||
- (void)handleTouchesMoved:(NSSet *)movedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event
|
||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
NSArray *indicesOfMoves = [self _indicesOfTouches:movedTouches inArray:_orderedTouches];
|
||||
NSArray *args =
|
||||
[RCTEventExtractor touchEventArgsForOrderedTouches:_orderedTouches
|
||||
orderedStartTags:_orderedTouchStartTags
|
||||
orderedTouchIDs:_orderedTouchIDs
|
||||
changedIndices:indicesOfMoves
|
||||
type:RCTEventTouchMove
|
||||
view:_rootView];
|
||||
[_eventDispatcher sendTouchesWithArgs:args];
|
||||
}
|
||||
|
||||
- (void)handleTouchesEnded:(NSSet *)endedTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event
|
||||
{
|
||||
NSArray *indicesOfEnds = [self _indicesOfTouches:endedTouches inArray:_orderedTouches];
|
||||
NSArray *args =
|
||||
[RCTEventExtractor touchEventArgsForOrderedTouches:_orderedTouches
|
||||
orderedStartTags:_orderedTouchStartTags
|
||||
orderedTouchIDs:_orderedTouchIDs
|
||||
changedIndices:indicesOfEnds
|
||||
type:RCTEventTouchEnd
|
||||
view:_rootView];
|
||||
[_eventDispatcher sendTouchesWithArgs:args];
|
||||
[self _recordRemovedTouches:endedTouches];
|
||||
}
|
||||
|
||||
- (void)handleTouchesCancelled:(NSSet *)cancelledTouches
|
||||
forMultiGestureRecognizer:(RCTMultiTouchGestureRecognizer *)multiTouchGestureRecognizer
|
||||
withEvent:(UIEvent *)event
|
||||
{
|
||||
NSArray *indicesOfCancels = [self _indicesOfTouches:cancelledTouches inArray:_orderedTouches];
|
||||
NSArray *args =
|
||||
[RCTEventExtractor touchEventArgsForOrderedTouches:_orderedTouches
|
||||
orderedStartTags:_orderedTouchStartTags
|
||||
orderedTouchIDs:_orderedTouchIDs
|
||||
changedIndices:indicesOfCancels
|
||||
type:RCTEventTouchCancel
|
||||
view:_rootView];
|
||||
[_eventDispatcher sendTouchesWithArgs:args];
|
||||
[self _recordRemovedTouches:cancelledTouches];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Needed simply to be provided to the `RCTMultiTouchGestureRecognizer`. If not,
|
||||
* other gestures are cancelled.
|
||||
*/
|
||||
- (void)handleMultiTouchGesture:(UIGestureRecognizer *)sender
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (NSDictionary *)_nativeEventForGesture:(UIGestureRecognizer *)sender
|
||||
target:(UIView *)target
|
||||
reactTargetView:(UIView *)reactTargetView
|
||||
{
|
||||
return @{
|
||||
@"state": @(sender.state),
|
||||
@"target": reactTargetView.reactTag,
|
||||
};
|
||||
}
|
||||
|
||||
- (void)handleTap:(UIGestureRecognizer *)sender
|
||||
{
|
||||
// This calculation may not be accurate when views overlap.
|
||||
UIView *touchedView = sender.view;
|
||||
CGPoint location = [sender locationInView:touchedView];
|
||||
UIView *target = [touchedView hitTest:location withEvent:nil];
|
||||
|
||||
// Views outside the RCT system can be present (e.g., UITableViewCellContentView)
|
||||
// they have no registry. we can safely ignore events happening on them.
|
||||
if (sender.state == UIGestureRecognizerStateEnded) {
|
||||
UIView *reactTargetView = [RCTUIManager closestReactAncestor:target];
|
||||
if (reactTargetView) {
|
||||
NSMutableDictionary *nativeEvent =[[self _nativeEventForGesture:sender target:target reactTargetView:reactTargetView] mutableCopy];
|
||||
nativeEvent[@"pageX"] = @(location.x);
|
||||
nativeEvent[@"pageY"] = @(location.y);
|
||||
CGPoint locInView = [sender.view convertPoint:location toView:target];
|
||||
nativeEvent[@"locationX"] = @(locInView.x);
|
||||
nativeEvent[@"locationY"] = @(locInView.y);
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[reactTargetView reactTag]
|
||||
type:RCTEventTap
|
||||
nativeEventObj:nativeEvent]];
|
||||
}
|
||||
[super touchesMoved:touches withEvent:event];
|
||||
if (self.state == UIGestureRecognizerStateFailed) {
|
||||
return;
|
||||
}
|
||||
[self _updateAndDispatchTouches:touches eventType:RCTTouchEventTypeMove];
|
||||
}
|
||||
|
||||
- (void)handleLongPress:(UIGestureRecognizer *)sender
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesEnded:touches withEvent:event];
|
||||
[self _updateAndDispatchTouches:touches eventType:RCTTouchEventTypeEnd];
|
||||
[self _recordRemovedTouches:touches];
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesCancelled:touches withEvent:event];
|
||||
[self _updateAndDispatchTouches:touches eventType:RCTTouchEventTypeCancel];
|
||||
[self _recordRemovedTouches:touches];
|
||||
}
|
||||
|
||||
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -33,7 +33,7 @@ static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
|
|||
if (!webView) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Can't init with a nil webview" userInfo:nil];
|
||||
}
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_objectsToInject = [[NSMutableDictionary alloc] init];
|
||||
_webView = webView;
|
||||
_webView.delegate = self;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
targetTime:(NSTimeInterval)targetTime
|
||||
repeats:(BOOL)repeats
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_active = YES;
|
||||
_interval = interval;
|
||||
_repeats = repeats;
|
||||
|
@ -62,7 +62,7 @@
|
|||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
_timers = [[RCTSparseArray alloc] init];
|
||||
}
|
||||
|
|
|
@ -5,20 +5,19 @@
|
|||
#import "RCTExport.h"
|
||||
#import "RCTInvalidating.h"
|
||||
|
||||
@class RCTAnimationRegistry;
|
||||
@class RCTRootView;
|
||||
@class RCTShadowView;
|
||||
|
||||
@protocol RCTScrollableProtocol;
|
||||
@protocol RCTViewNodeProtocol;
|
||||
|
||||
@class RCTRootView;
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTShadowView;
|
||||
@class RCTAnimationRegistry;
|
||||
|
||||
@interface RCTUIManager : NSObject <RCTInvalidating, RCTNativeModule>
|
||||
|
||||
- (instancetype)initWithShadowQueue:(dispatch_queue_t)shadowQueue
|
||||
viewManagers:(NSDictionary *)viewManagers;
|
||||
|
||||
@property (nonatomic, strong) RCTJavaScriptEventDispatcher *eventDispatcher;
|
||||
@property (nonatomic, strong) RCTEventDispatcher *eventDispatcher;
|
||||
@property (nonatomic, strong) RCTSparseArray *shadowViewRegistry;
|
||||
@property (nonatomic, strong) RCTSparseArray *viewRegistry;
|
||||
@property (nonatomic, strong) RCTAnimationRegistry *animationRegistry;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <objc/message.h>
|
||||
#import <pthread/pthread.h>
|
||||
#import <pthread.h>
|
||||
|
||||
#import "Layout.h"
|
||||
#import "RCTAssert.h"
|
||||
|
@ -26,7 +26,8 @@
|
|||
|
||||
typedef void (^react_view_node_block_t)(id<RCTViewNodeProtocol>);
|
||||
|
||||
static void RCTTraverseViewNodes(id<RCTViewNodeProtocol> view, react_view_node_block_t block) {
|
||||
static void RCTTraverseViewNodes(id<RCTViewNodeProtocol> view, react_view_node_block_t block)
|
||||
{
|
||||
if (view.reactTag) block(view);
|
||||
for (id<RCTViewNodeProtocol> subview in view.reactSubviews) {
|
||||
RCTTraverseViewNodes(subview, block);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
137029491A698FF000575408 /* RCTNetworkImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137029401A698FF000575408 /* RCTNetworkImageViewManager.m */; };
|
||||
137029501A6990A100575408 /* RCTNetworkImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1370294F1A6990A100575408 /* RCTNetworkImageView.m */; };
|
||||
137029531A69923600575408 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 137029521A69923600575408 /* RCTImageDownloader.m */; };
|
||||
137029561A6C17DC00575408 /* RCTScrollDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 137029551A6C17DC00575408 /* RCTScrollDispatcher.m */; };
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
|
||||
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FE81A69327A00A75B9A /* RCTAlertManager.m */; };
|
||||
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */; };
|
||||
|
@ -49,13 +48,11 @@
|
|||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA501A601E3B00E9B192 /* RCTUtils.m */; };
|
||||
83CBBA5A1A601E9000E9B192 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA591A601E9000E9B192 /* RCTRedBox.m */; };
|
||||
83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA5F1A601EAA00E9B192 /* RCTBridge.m */; };
|
||||
83CBBA691A601EF300E9B192 /* RCTJavaScriptEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTJavaScriptEventDispatcher.m */; };
|
||||
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
|
||||
83CBBA871A60202500E9B192 /* RCTJavaScriptAppEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA861A60202500E9B192 /* RCTJavaScriptAppEngine.m */; };
|
||||
83CBBA8B1A60204600E9B192 /* RCTModuleIDs.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA8A1A60204600E9B192 /* RCTModuleIDs.m */; };
|
||||
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
|
||||
83CBBAA11A60215500E9B192 /* RCTEventExtractor.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBAA01A60215500E9B192 /* RCTEventExtractor.m */; };
|
||||
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
|
||||
83CBBAD81A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBAD71A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.m */; };
|
||||
83EEC2EE1A604AB200C39218 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 83EEC2ED1A604AB200C39218 /* RCTModuleMethod.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -87,8 +84,6 @@
|
|||
1370294F1A6990A100575408 /* RCTNetworkImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNetworkImageView.m; sourceTree = "<group>"; };
|
||||
137029511A69923600575408 /* RCTImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageDownloader.h; sourceTree = "<group>"; };
|
||||
137029521A69923600575408 /* RCTImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageDownloader.m; sourceTree = "<group>"; };
|
||||
137029541A6C17DC00575408 /* RCTScrollDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTScrollDispatcher.h; sourceTree = "<group>"; };
|
||||
137029551A6C17DC00575408 /* RCTScrollDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTScrollDispatcher.m; sourceTree = "<group>"; };
|
||||
137029571A6C197000575408 /* RCTRawTextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextManager.h; sourceTree = "<group>"; };
|
||||
137029581A6C197000575408 /* RCTRawTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextManager.m; sourceTree = "<group>"; };
|
||||
13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = "<group>"; };
|
||||
|
@ -163,20 +158,16 @@
|
|||
83CBBA611A601EB200E9B192 /* RCTAutoInsetsProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTAutoInsetsProtocol.h; sourceTree = "<group>"; };
|
||||
83CBBA621A601EB800E9B192 /* RCTViewNodeProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTViewNodeProtocol.h; sourceTree = "<group>"; };
|
||||
83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptExecutor.h; sourceTree = "<group>"; };
|
||||
83CBBA651A601EF300E9B192 /* RCTJavaScriptEventDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptEventDispatcher.h; sourceTree = "<group>"; };
|
||||
83CBBA661A601EF300E9B192 /* RCTJavaScriptEventDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJavaScriptEventDispatcher.m; sourceTree = "<group>"; };
|
||||
83CBBA651A601EF300E9B192 /* RCTEventDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTEventDispatcher.h; sourceTree = "<group>"; };
|
||||
83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventDispatcher.m; sourceTree = "<group>"; };
|
||||
83CBBA851A60202500E9B192 /* RCTJavaScriptAppEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptAppEngine.h; sourceTree = "<group>"; };
|
||||
83CBBA861A60202500E9B192 /* RCTJavaScriptAppEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJavaScriptAppEngine.m; sourceTree = "<group>"; };
|
||||
83CBBA891A60204600E9B192 /* RCTModuleIDs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleIDs.h; sourceTree = "<group>"; };
|
||||
83CBBA8A1A60204600E9B192 /* RCTModuleIDs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleIDs.m; sourceTree = "<group>"; };
|
||||
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTouchHandler.h; sourceTree = "<group>"; };
|
||||
83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTouchHandler.m; sourceTree = "<group>"; };
|
||||
83CBBA9F1A60215500E9B192 /* RCTEventExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTEventExtractor.h; sourceTree = "<group>"; };
|
||||
83CBBAA01A60215500E9B192 /* RCTEventExtractor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventExtractor.m; sourceTree = "<group>"; };
|
||||
83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTConvert.h; sourceTree = "<group>"; };
|
||||
83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
|
||||
83CBBAD61A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultiTouchGestureRecognizer.h; sourceTree = "<group>"; };
|
||||
83CBBAD71A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultiTouchGestureRecognizer.m; sourceTree = "<group>"; };
|
||||
83EEC2EC1A604AB200C39218 /* RCTModuleMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleMethod.h; sourceTree = "<group>"; };
|
||||
83EEC2ED1A604AB200C39218 /* RCTModuleMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMethod.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
@ -324,8 +315,6 @@
|
|||
83EEC2ED1A604AB200C39218 /* RCTModuleMethod.m */,
|
||||
83CBBACA1A6023D300E9B192 /* RCTConvert.h */,
|
||||
83CBBACB1A6023D300E9B192 /* RCTConvert.m */,
|
||||
83CBBA9F1A60215500E9B192 /* RCTEventExtractor.h */,
|
||||
83CBBAA01A60215500E9B192 /* RCTEventExtractor.m */,
|
||||
830213F31A654E0800B993E6 /* RCTExport.h */,
|
||||
830213F41A65574D00B993E6 /* RCTExport.m */,
|
||||
830A229C1A66C68A008503DA /* RCTRootView.h */,
|
||||
|
@ -333,8 +322,8 @@
|
|||
83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */,
|
||||
83CBBA851A60202500E9B192 /* RCTJavaScriptAppEngine.h */,
|
||||
83CBBA861A60202500E9B192 /* RCTJavaScriptAppEngine.m */,
|
||||
83CBBA651A601EF300E9B192 /* RCTJavaScriptEventDispatcher.h */,
|
||||
83CBBA661A601EF300E9B192 /* RCTJavaScriptEventDispatcher.m */,
|
||||
83CBBA651A601EF300E9B192 /* RCTEventDispatcher.h */,
|
||||
83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */,
|
||||
83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
|
||||
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
|
||||
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */,
|
||||
|
@ -342,8 +331,6 @@
|
|||
83CBBA4E1A601E3B00E9B192 /* RCTLog.m */,
|
||||
83CBBA891A60204600E9B192 /* RCTModuleIDs.h */,
|
||||
83CBBA8A1A60204600E9B192 /* RCTModuleIDs.m */,
|
||||
83CBBAD61A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.h */,
|
||||
83CBBAD71A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.m */,
|
||||
83CBBA581A601E9000E9B192 /* RCTRedBox.h */,
|
||||
83CBBA591A601E9000E9B192 /* RCTRedBox.m */,
|
||||
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
|
||||
|
@ -354,8 +341,6 @@
|
|||
137029511A69923600575408 /* RCTImageDownloader.h */,
|
||||
137029521A69923600575408 /* RCTImageDownloader.m */,
|
||||
13B07FCD1A683B5F00A75B9A /* RCTScrollableProtocol.h */,
|
||||
137029541A6C17DC00575408 /* RCTScrollDispatcher.h */,
|
||||
137029551A6C17DC00575408 /* RCTScrollDispatcher.m */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
|
@ -461,12 +446,10 @@
|
|||
137029501A6990A100575408 /* RCTNetworkImageView.m in Sources */,
|
||||
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
|
||||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */,
|
||||
83CBBAD81A60250F00E9B192 /* RCTMultiTouchGestureRecognizer.m in Sources */,
|
||||
137029491A698FF000575408 /* RCTNetworkImageViewManager.m in Sources */,
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
|
||||
13E067581A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
|
||||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */,
|
||||
137029561A6C17DC00575408 /* RCTScrollDispatcher.m in Sources */,
|
||||
83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */,
|
||||
13B080081A6947C200A75B9A /* RCTShadowText.m in Sources */,
|
||||
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */,
|
||||
|
@ -476,8 +459,7 @@
|
|||
83EEC2EE1A604AB200C39218 /* RCTModuleMethod.m in Sources */,
|
||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||
137029331A69659C00575408 /* RCTExport.m in Sources */,
|
||||
83CBBA691A601EF300E9B192 /* RCTJavaScriptEventDispatcher.m in Sources */,
|
||||
83CBBAA11A60215500E9B192 /* RCTEventExtractor.m in Sources */,
|
||||
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
|
||||
134FCB371A6D4ED700051CC8 /* RCTRawTextManager.m in Sources */,
|
||||
13B0800B1A6947C200A75B9A /* RCTTextManager.m in Sources */,
|
||||
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
@implementation RCTNavItemManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTNavItem alloc] initWithFrame:CGRectZero];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTNavigator : UIView <UINavigationControllerDelegate>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
|||
@property (nonatomic, assign) NSInteger requestedTopOfStack;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
/**
|
||||
* Schedules a JavaScript navigation and prevents `UIKit` from navigating until
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTNavItem.h"
|
||||
#import "RCTUtils.h"
|
||||
|
@ -138,7 +137,7 @@ NSInteger kNeverProgressed = -10000;
|
|||
*/
|
||||
- (instancetype)initWithScrollCallback:(dispatch_block_t)callback
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if ((self = [super init])) {
|
||||
_scrollCallback = callback;
|
||||
}
|
||||
return self;
|
||||
|
@ -193,7 +192,7 @@ NSInteger kNeverProgressed = -10000;
|
|||
|
||||
@interface RCTNavigator() <RCTWrapperViewControllerNavigationListener>
|
||||
{
|
||||
RCTJavaScriptEventDispatcher *_eventDispatcher;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
NSInteger _numberOfViewControllerMovesToIgnore;
|
||||
}
|
||||
|
||||
|
@ -267,7 +266,7 @@ NSInteger kNeverProgressed = -10000;
|
|||
@implementation RCTNavigator
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
|
@ -311,16 +310,12 @@ NSInteger kNeverProgressed = -10000;
|
|||
if (nextProgress == _mostRecentProgress) {
|
||||
return;
|
||||
}
|
||||
NSDictionary *nativeEventObj = @{
|
||||
@"fromIndex": @(_currentlyTransitioningFrom),
|
||||
@"toIndex": @(_currentlyTransitioningTo),
|
||||
@"progress": @(nextProgress),
|
||||
@"target": self.reactTag ?: @0,
|
||||
};
|
||||
_mostRecentProgress = nextProgress;
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:self.reactTag
|
||||
type:RCTEventNavigationProgress
|
||||
nativeEventObj:nativeEventObj]];
|
||||
[_eventDispatcher sendRawEventWithType:@"topNavigationProgress"
|
||||
body:@{@"fromIndex": @(_currentlyTransitioningFrom),
|
||||
@"toIndex": @(_currentlyTransitioningTo),
|
||||
@"progress": @(nextProgress),
|
||||
@"target": self.reactTag}];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,21 +438,17 @@ NSInteger kNeverProgressed = -10000;
|
|||
|
||||
- (void)handleTopOfStackChanged
|
||||
{
|
||||
NSDictionary *nativeEventObj = @{
|
||||
@"target":self.reactTag ?: @0,
|
||||
@"stackLength":@(_navigationController.viewControllers.count)
|
||||
};
|
||||
NSArray *eventArgs = [RCTEventExtractor eventArgs:self.reactTag
|
||||
type:RCTEventNavigateBack
|
||||
nativeEventObj:nativeEventObj];
|
||||
[_eventDispatcher sendEventWithArgs:eventArgs];
|
||||
[_eventDispatcher sendRawEventWithType:@"topNavigateBack"
|
||||
body:@{@"target":self.reactTag,
|
||||
@"stackLength":@(_navigationController.viewControllers.count)}];
|
||||
}
|
||||
|
||||
- (void)dispatchFakeScrollEvent
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventScroll
|
||||
nativeEventObj:[RCTEventExtractor fakeScrollEventObjectFor:[self reactTag]]]];
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeMove
|
||||
reactTag:self.reactTag
|
||||
scrollView:nil
|
||||
userData:nil];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@implementation RCTNavigatorManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTNavigator alloc] initWithFrame:CGRectZero eventDispatcher:eventDispatcher];
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
@implementation RCTNetworkImageViewManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
RCTNetworkImageView *view = [[RCTNetworkImageView alloc] initWithFrame:CGRectZero imageDownloader:[RCTImageDownloader sharedInstance]];
|
||||
view.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@implementation RCTRawTextManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[UIView alloc] init];
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@protocol UIScrollViewDelegate;
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTScrollView : RCTView <UIScrollViewDelegate, RCTScrollableProtocol, RCTAutoInsetsProtocol>
|
||||
|
||||
|
@ -32,6 +32,6 @@
|
|||
@property (nonatomic, assign) BOOL centerContent;
|
||||
@property (nonatomic, copy) NSArray *stickyHeaderIndices;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
@end
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTScrollDispatcher.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
|
@ -249,24 +247,20 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
|
||||
@end
|
||||
|
||||
@interface RCTScrollView ()
|
||||
@implementation RCTScrollView
|
||||
{
|
||||
RCTJavaScriptEventDispatcher *_eventDispatcher;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
BOOL _contentSizeManuallySet;
|
||||
RCTScrollDispatcher *_scrollDispatcher;
|
||||
RCTCustomScrollView *_scrollView;
|
||||
UIView *_contentView;
|
||||
NSTimeInterval _lastScrollDispatchTime;
|
||||
NSMutableArray *_cachedChildFrames;
|
||||
BOOL _allowNextScrollNoMatterWhat;
|
||||
}
|
||||
|
||||
@property (nonatomic, readwrite, assign) BOOL didThrottleMomentumScrollEvent;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTScrollView
|
||||
|
||||
@synthesize nativeMainScrollDelegate = _nativeMainScrollDelegate;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
|
||||
|
@ -274,9 +268,12 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
_scrollView = [[RCTCustomScrollView alloc] initWithFrame:CGRectZero];
|
||||
_scrollView.delegate = self;
|
||||
_scrollView.delaysContentTouches = NO;
|
||||
_scrollDispatcher = [[RCTScrollDispatcher alloc] initWithEventDispatcher:eventDispatcher];
|
||||
_automaticallyAdjustContentInsets = YES;
|
||||
_contentInset = UIEdgeInsetsZero;
|
||||
|
||||
_throttleScrollCallbackMS = 0;
|
||||
_lastScrollDispatchTime = CACurrentMediaTime();
|
||||
_cachedChildFrames = [[NSMutableArray alloc] init];
|
||||
|
||||
[self addSubview:_scrollView];
|
||||
}
|
||||
|
@ -371,90 +368,120 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
[_scrollView zoomToRect:rect animated:animated];
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate methods
|
||||
#pragma mark - ScrollView delegate
|
||||
|
||||
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
|
||||
{
|
||||
[_scrollDispatcher scrollViewDidEndScrollingAnimation:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidEndScrollingAnimation:scrollView];
|
||||
}
|
||||
#define RCT_SCROLL_EVENT_HANDLER(delegateMethod, eventName) \
|
||||
- (void)delegateMethod:(UIScrollView *)scrollView \
|
||||
{ \
|
||||
[_eventDispatcher sendScrollEventWithType:eventName reactTag:self.reactTag scrollView:scrollView userData:nil]; \
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) { \
|
||||
[_nativeMainScrollDelegate delegateMethod:scrollView]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RCT_FORWARD_SCROLL_EVENT(call) \
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) { \
|
||||
[_nativeMainScrollDelegate call]; \
|
||||
}
|
||||
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewDidEndScrollingAnimation, RCTScrollEventTypeEndDeceleration)
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, RCTScrollEventTypeStartDeceleration)
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewDidEndDecelerating, RCTScrollEventTypeEndDeceleration)
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, RCTScrollEventTypeMove)
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[_scrollDispatcher scrollViewDidScroll:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidScroll:scrollView];
|
||||
}
|
||||
}
|
||||
NSTimeInterval now = CACurrentMediaTime();
|
||||
NSTimeInterval throttleScrollCallbackSeconds = _throttleScrollCallbackMS / 1000.0;
|
||||
|
||||
/**
|
||||
* TODO: this logic looks wrong, and it may be because it is. Currently, if _throttleScrollCallbackMS
|
||||
* is set to zero (the default), the "didScroll" event is only sent once per scroll, instead of repeatedly
|
||||
* while scrolling as expected. However, if you "fix" that bug, ScrollView will generate repeated
|
||||
* warnings, and behave strangely (ListView works fine however), so don't fix it unless you fix that too!
|
||||
*/
|
||||
if (_allowNextScrollNoMatterWhat ||
|
||||
(_throttleScrollCallbackMS != 0 && throttleScrollCallbackSeconds < (now - _lastScrollDispatchTime))) {
|
||||
|
||||
// Calculate changed frames
|
||||
NSMutableArray *updatedChildFrames = [[NSMutableArray alloc] init];
|
||||
[[_contentView reactSubviews] enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) {
|
||||
|
||||
// Check if new or changed
|
||||
CGRect newFrame = subview.frame;
|
||||
BOOL frameChanged = NO;
|
||||
if (_cachedChildFrames.count <= idx) {
|
||||
frameChanged = YES;
|
||||
[_cachedChildFrames addObject:[NSValue valueWithCGRect:newFrame]];
|
||||
} else if (!CGRectEqualToRect(newFrame, [_cachedChildFrames[idx] CGRectValue])) {
|
||||
frameChanged = YES;
|
||||
_cachedChildFrames[idx] = [NSValue valueWithCGRect:newFrame];
|
||||
}
|
||||
|
||||
// Create JS frame object
|
||||
if (frameChanged) {
|
||||
[updatedChildFrames addObject: @{
|
||||
@"index": @(idx),
|
||||
@"x": @(newFrame.origin.x),
|
||||
@"y": @(newFrame.origin.y),
|
||||
@"width": @(newFrame.size.width),
|
||||
@"height": @(newFrame.size.height),
|
||||
}];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// If there are new frames, add them to event data
|
||||
NSDictionary *userData = nil;
|
||||
if (updatedChildFrames.count > 0) {
|
||||
userData = @{@"updatedChildFrames": updatedChildFrames};
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
|
||||
{
|
||||
[_scrollDispatcher scrollViewWillBeginDecelerating:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewWillBeginDecelerating:scrollView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
|
||||
{
|
||||
[_scrollDispatcher scrollViewDidEndDecelerating:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidEndDecelerating:scrollView];
|
||||
// Dispatch event
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeMove
|
||||
reactTag:self.reactTag
|
||||
scrollView:scrollView
|
||||
userData:userData];
|
||||
// Update dispatch time
|
||||
_lastScrollDispatchTime = now;
|
||||
_allowNextScrollNoMatterWhat = NO;
|
||||
}
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewDidScroll:scrollView);
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
{
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewWillBeginDragging:scrollView];
|
||||
}
|
||||
[_scrollDispatcher scrollViewWillBeginDragging:_scrollView reactTag:[self reactTag]];
|
||||
_allowNextScrollNoMatterWhat = YES; // Ensure next scroll event is recorded, regardless of throttle
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeStart reactTag:self.reactTag scrollView:scrollView userData:nil];
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewWillBeginDragging:scrollView);
|
||||
}
|
||||
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
|
||||
{
|
||||
[_scrollDispatcher scrollViewWillEndDragging:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
||||
}
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeEnd reactTag:self.reactTag scrollView:scrollView userData:nil];
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset);
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
|
||||
{
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
|
||||
{
|
||||
[_scrollDispatcher scrollViewDidScroll:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidZoom:scrollView];
|
||||
}
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndDragging:scrollView willDecelerate:decelerate);
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
|
||||
{
|
||||
[_scrollDispatcher scrollViewWillBeginDragging:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewWillBeginZooming:scrollView withView:view];
|
||||
}
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeStart reactTag:self.reactTag scrollView:scrollView userData:nil];
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewWillBeginZooming:scrollView withView:view);
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
|
||||
{
|
||||
[_scrollDispatcher scrollViewWillEndDragging:_scrollView reactTag:[self reactTag]];
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) {
|
||||
[_nativeMainScrollDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale];
|
||||
}
|
||||
[_eventDispatcher sendScrollEventWithType:RCTScrollEventTypeEnd reactTag:self.reactTag scrollView:scrollView userData:nil];
|
||||
RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndZooming:scrollView withView:view atScale:scale);
|
||||
}
|
||||
|
||||
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
|
||||
{
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) {
|
||||
if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) {
|
||||
return [_nativeMainScrollDelegate scrollViewShouldScrollToTop:scrollView];
|
||||
}
|
||||
return YES;
|
||||
|
@ -467,11 +494,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setThrottleScrollCallbackMS:(NSUInteger)ms
|
||||
{
|
||||
_scrollDispatcher.throttleScrollCallbackMS = ms;
|
||||
}
|
||||
|
||||
- (CGSize)_calculateViewportSize
|
||||
{
|
||||
CGSize viewportSize = self.bounds.size;
|
||||
|
@ -527,27 +549,24 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
{
|
||||
if (_contentSizeManuallySet) {
|
||||
_scrollView.contentSize = _contentSize;
|
||||
} else if (!_contentView) {
|
||||
_scrollView.contentSize = CGSizeZero;
|
||||
} else {
|
||||
if (!_contentView) {
|
||||
_scrollView.contentSize = CGSizeZero;
|
||||
} else {
|
||||
CGSize singleSubviewSize = _contentView.frame.size;
|
||||
CGPoint singleSubviewPosition = _contentView.frame.origin;
|
||||
CGSize fittedSize = CGSizeMake(
|
||||
singleSubviewSize.width + singleSubviewPosition.x,
|
||||
singleSubviewSize.height + singleSubviewPosition.y
|
||||
);
|
||||
if (!CGSizeEqualToSize(_scrollView.contentSize, fittedSize)) {
|
||||
// When contentSize is set manually, ScrollView internals will reset contentOffset to 0,0. Since
|
||||
// we potentially set contentSize whenever anything in the ScrollView updates, we workaround this
|
||||
// issue by manually adjusting contentOffset whenever this happens
|
||||
CGPoint newOffset = [self calculateOffsetForContentSize:fittedSize];
|
||||
_scrollView.contentSize = fittedSize;
|
||||
_scrollView.contentOffset = newOffset;
|
||||
}
|
||||
// when react makes changes to our
|
||||
[_scrollView dockClosestSectionHeader];
|
||||
CGSize singleSubviewSize = _contentView.frame.size;
|
||||
CGPoint singleSubviewPosition = _contentView.frame.origin;
|
||||
CGSize fittedSize = {
|
||||
singleSubviewSize.width + singleSubviewPosition.x,
|
||||
singleSubviewSize.height + singleSubviewPosition.y
|
||||
};
|
||||
if (!CGSizeEqualToSize(_scrollView.contentSize, fittedSize)) {
|
||||
// When contentSize is set manually, ScrollView internals will reset contentOffset to 0,0. Since
|
||||
// we potentially set contentSize whenever anything in the ScrollView updates, we workaround this
|
||||
// issue by manually adjusting contentOffset whenever this happens
|
||||
CGPoint newOffset = [self calculateOffsetForContentSize:fittedSize];
|
||||
_scrollView.contentSize = fittedSize;
|
||||
_scrollView.contentOffset = newOffset;
|
||||
}
|
||||
[_scrollView dockClosestSectionHeader];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
@implementation RCTScrollViewManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTScrollView alloc] initWithFrame:CGRectZero eventDispatcher:eventDispatcher];
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ RCT_EXPORT_VIEW_PROPERTY(stickyHeaderIndices);
|
|||
RCT_EXPORT_VIEW_PROPERTY(throttleScrollCallbackMS);
|
||||
RCT_EXPORT_VIEW_PROPERTY(zoomScale);
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentInset);
|
||||
RCT_REMAP_VIEW_PROPERTY(scrollIndicatorInsets, scrollView.scrollIndicatorInsets);
|
||||
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffse);
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets);
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentOffset);
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
{
|
||||
|
|
|
@ -183,17 +183,17 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
|||
node->layout.should_update = false;
|
||||
_layoutLifecycle = RCTLayoutLifecycleComputed;
|
||||
|
||||
CGPoint absoluteTopLeft = (CGPoint){
|
||||
CGPoint absoluteTopLeft = {
|
||||
RCTRoundPixelValue(absolutePosition.x + node->layout.position[CSS_LEFT]),
|
||||
RCTRoundPixelValue(absolutePosition.y + node->layout.position[CSS_TOP])
|
||||
};
|
||||
|
||||
CGPoint absoluteBottomRight = (CGPoint){
|
||||
CGPoint absoluteBottomRight = {
|
||||
RCTRoundPixelValue(absolutePosition.x + node->layout.position[CSS_LEFT] + node->layout.dimensions[CSS_WIDTH]),
|
||||
RCTRoundPixelValue(absolutePosition.y + node->layout.position[CSS_TOP] + node->layout.dimensions[CSS_HEIGHT])
|
||||
};
|
||||
|
||||
CGRect frame = (CGRect){
|
||||
CGRect frame = {
|
||||
RCTRoundPixelValue(node->layout.position[CSS_LEFT]),
|
||||
RCTRoundPixelValue(node->layout.position[CSS_TOP]),
|
||||
RCTRoundPixelValue(absoluteBottomRight.x - absoluteTopLeft.x),
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
@implementation RCTStaticImageManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTStaticImage alloc] init];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTTextField : UITextField
|
||||
|
||||
|
@ -10,6 +10,6 @@
|
|||
@property (nonatomic, assign) BOOL autoCorrect;
|
||||
@property (nonatomic, assign) UIEdgeInsets paddingEdgeInsets; // TODO: contentInset
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
@end
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
#import "RCTTextField.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTTextField
|
||||
{
|
||||
RCTJavaScriptEventDispatcher *_eventDispatcher;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
NSMutableArray *_reactSubviews;
|
||||
BOOL _jsRequestingFirstResponder;
|
||||
}
|
||||
|
@ -20,33 +19,41 @@
|
|||
RCT_NOT_DESIGNATED_INITIALIZER();
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithFrame:(CGRect)frame eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
|
||||
_eventDispatcher = eventDispatcher;
|
||||
[self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
|
||||
[self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
|
||||
[self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
|
||||
[self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||
_reactSubviews = [[NSMutableArray alloc] init];
|
||||
self.returnKeyType = UIReturnKeyDone;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)reactSubviews
|
||||
{
|
||||
// TODO: do we support subviews of textfield in React?
|
||||
// In any case, we should have a better approach than manually
|
||||
// maintaining array in each view subclass like this
|
||||
return _reactSubviews;
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
// TODO: this is a bit broken - if the TextView inserts any of
|
||||
// it's own views below or between React's, the indices won't match
|
||||
[_reactSubviews removeObject:subview];
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
|
||||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||
{
|
||||
// TODO: this is a bit broken - if the TextView inserts any of
|
||||
// it's own views below or between React's, the indices won't match
|
||||
[_reactSubviews insertObject:view atIndex:atIndex];
|
||||
[super insertSubview:view atIndex:atIndex];
|
||||
}
|
||||
|
@ -56,7 +63,6 @@
|
|||
if (_caretHidden) {
|
||||
return CGRectZero;
|
||||
}
|
||||
|
||||
return [super caretRectForPosition:position];
|
||||
}
|
||||
|
||||
|
@ -81,72 +87,45 @@
|
|||
return self.autocorrectionType == UITextAutocorrectionTypeYes;
|
||||
}
|
||||
|
||||
- (void)_textFieldDidChange
|
||||
{
|
||||
[self handleTextChange];
|
||||
#define RCT_TEXT_EVENT_HANDLER(delegateMethod, eventName) \
|
||||
- (void)delegateMethod \
|
||||
{ \
|
||||
[_eventDispatcher sendTextEventWithType:eventName \
|
||||
reactTag:self.reactTag \
|
||||
text:self.text]; \
|
||||
}
|
||||
|
||||
- (void)_textFieldEndEditing
|
||||
{
|
||||
NSDictionary *event = @{@"text": self.text, @"target": self.reactTag};
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventTextFieldEndEditing
|
||||
nativeEventObj:event]];
|
||||
}
|
||||
RCT_TEXT_EVENT_HANDLER(_textFieldDidChange, RCTTextEventTypeChange)
|
||||
RCT_TEXT_EVENT_HANDLER(_textFieldBeginEditing, RCTTextEventTypeFocus)
|
||||
RCT_TEXT_EVENT_HANDLER(_textFieldEndEditing, RCTTextEventTypeEnd)
|
||||
RCT_TEXT_EVENT_HANDLER(_textFieldSubmitEditing, RCTTextEventTypeSubmit)
|
||||
|
||||
- (void)_textFieldSubmitEditing
|
||||
{
|
||||
NSDictionary *event = @{@"text": self.text, @"target": self.reactTag};
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventTextFieldSubmitEditing
|
||||
nativeEventObj:event]];
|
||||
}
|
||||
// TODO: we should support shouldChangeTextInRect (see UITextFieldDelegate)
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
_jsRequestingFirstResponder = YES;
|
||||
BOOL wasPreviouslyResponder = [self isFirstResponder];
|
||||
BOOL ret = [super becomeFirstResponder];
|
||||
BOOL isTransitioningResponder = !wasPreviouslyResponder && ret;
|
||||
if (isTransitioningResponder) {
|
||||
[self handleTextFieldDidFocus];
|
||||
}
|
||||
_jsRequestingFirstResponder = YES; // TODO: is this still needed?
|
||||
BOOL result = [super becomeFirstResponder];
|
||||
_jsRequestingFirstResponder = NO;
|
||||
return ret;
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
[self handleTextFieldWillBlur];
|
||||
return [super resignFirstResponder];
|
||||
BOOL result = [super resignFirstResponder];
|
||||
if (result)
|
||||
{
|
||||
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur
|
||||
reactTag:self.reactTag
|
||||
text:self.text];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Prevent native from becoming first responder
|
||||
// Prevent native from becoming first responder (TODO: why?)
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return _jsRequestingFirstResponder;
|
||||
}
|
||||
|
||||
- (void)handleTextChange
|
||||
{
|
||||
NSDictionary *event = @{@"text": self.text, @"target": self.reactTag};
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventChange
|
||||
nativeEventObj:event]];
|
||||
}
|
||||
|
||||
- (void)handleTextFieldDidFocus
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventTextFieldDidFocus
|
||||
nativeEventObj:@{@"target":self.reactTag}]];
|
||||
}
|
||||
|
||||
- (void)handleTextFieldWillBlur
|
||||
{
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[self reactTag]
|
||||
type:RCTEventTextFieldWillBlur
|
||||
nativeEventObj:@{@"target":self.reactTag}]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@implementation RCTTextFieldManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTTextField alloc] initWithFrame:CGRectZero eventDispatcher:eventDispatcher];
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
@implementation RCTTextManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.numberOfLines = 0;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@implementation RCTUIActivityIndicatorViewManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
@implementation RCTUIViewManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[UIView alloc] init];
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@implementation RCTViewManager
|
||||
|
||||
- (UIView *)viewWithEventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (UIView *)viewWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return [[RCTView alloc] init];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTJavaScriptEventDispatcher;
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTNavItem;
|
||||
@class RCTWrapperViewController;
|
||||
|
||||
|
@ -15,8 +15,8 @@ didMoveToNavigationController:(UINavigationController *)navigationController;
|
|||
|
||||
@interface RCTWrapperViewController : UIViewController
|
||||
|
||||
- (instancetype)initWithContentView:(UIView *)contentView eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher;
|
||||
- (instancetype)initWithContentView:(UIView *)contentView eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
@property (nonatomic, readwrite, weak) id<RCTWrapperViewControllerNavigationListener> navigationListener;
|
||||
@property (nonatomic, strong, readwrite) RCTNavItem *navItem;
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#import "RCTWrapperViewController.h"
|
||||
|
||||
#import "RCTEventExtractor.h"
|
||||
#import "RCTJavaScriptEventDispatcher.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTNavItem.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
@ -11,7 +10,7 @@
|
|||
@implementation RCTWrapperViewController
|
||||
{
|
||||
UIView *_contentView;
|
||||
RCTJavaScriptEventDispatcher *_eventDispatcher;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
CGFloat _previousTopLayout;
|
||||
CGFloat _previousBottomLayout;
|
||||
}
|
||||
|
@ -21,9 +20,9 @@
|
|||
RCT_NOT_DESIGNATED_INITIALIZER();
|
||||
}
|
||||
|
||||
- (instancetype)initWithContentView:(UIView *)contentView eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithContentView:(UIView *)contentView eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if (self = [super initWithNibName:nil bundle:nil]) {
|
||||
if ((self = [super initWithNibName:nil bundle:nil])) {
|
||||
_contentView = contentView;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
|
@ -31,9 +30,9 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem eventDispatcher:(RCTJavaScriptEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if (self = [self initWithContentView:navItem eventDispatcher:eventDispatcher]) {
|
||||
if ((self = [self initWithContentView:navItem eventDispatcher:eventDispatcher])) {
|
||||
_navItem = navItem;
|
||||
}
|
||||
return self;
|
||||
|
@ -57,7 +56,7 @@
|
|||
[[UIBarButtonItem alloc] initWithTitle:_navItem.rightButtonTitle
|
||||
style:UIBarButtonItemStyleDone
|
||||
target:self
|
||||
action:@selector(_onRightButtonTapped:)];
|
||||
action:@selector(rightButtonTapped)];
|
||||
}
|
||||
|
||||
if (_navItem.backButtonTitle.length > 0) {
|
||||
|
@ -95,20 +94,9 @@
|
|||
[self.view addSubview:_contentView];
|
||||
}
|
||||
|
||||
- (void)_onRightButtonTapped:(id)sender
|
||||
- (void)rightButtonTapped
|
||||
{
|
||||
RCTAssert(_navItem != nil, @"");
|
||||
[self handleNavRightButtonTapped];
|
||||
}
|
||||
|
||||
- (void)handleNavRightButtonTapped
|
||||
{
|
||||
NSDictionary *nativeEvent = @{
|
||||
@"target":_navItem.reactTag
|
||||
};
|
||||
[_eventDispatcher sendEventWithArgs:[RCTEventExtractor eventArgs:[_navItem reactTag]
|
||||
type:RCTEventNavRightButtonTap
|
||||
nativeEventObj:nativeEvent]];
|
||||
[_eventDispatcher sendRawEventWithType:@"topNavRightButtonTap" body:@{@"target":_navItem.reactTag}];
|
||||
}
|
||||
|
||||
- (void)didMoveToParentViewController:(UIViewController *)parent
|
||||
|
|
Loading…
Reference in New Issue