mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-24 04:25:34 +08:00
Restore first responder of view controller when screen reactivates (#48)
This change automates first responder restoring when screen is deactivated and the activated back (e.g. when we push new screen on top and then go back). In addition we disable pointerEvent setting for the Screen component as changes made to that prop would cause underlying views to resign responder before we can remember it. Because of that we add an automatic handling for pointer events for the Screen component that disables all touch interactions when screen is transitioning.
This commit is contained in:
committed by
GitHub
parent
5dadab9aa6
commit
5893d9a8a7
@@ -13,6 +13,8 @@
|
||||
@property (nonatomic, retain) UIViewController *controller;
|
||||
@property (nonatomic) BOOL active;
|
||||
|
||||
- (void)notifyFinishTransitioning;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIView (RNSScreen)
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
@interface RNSScreen : UIViewController
|
||||
|
||||
- (instancetype)initWithView:(UIView *)view;
|
||||
- (void)notifyFinishTransitioning;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNSScreenView
|
||||
@implementation RNSScreenView {
|
||||
RNSScreen *_controller;
|
||||
}
|
||||
|
||||
@synthesize controller = _controller;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
@@ -37,10 +42,16 @@
|
||||
_controller = nil;
|
||||
}
|
||||
|
||||
- (void)notifyFinishTransitioning
|
||||
{
|
||||
[_controller notifyFinishTransitioning];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNSScreen {
|
||||
__weak UIView *_view;
|
||||
__weak id _previousFirstResponder;
|
||||
}
|
||||
|
||||
- (instancetype)initWithView:(UIView *)view
|
||||
@@ -51,6 +62,36 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)findFirstResponder:(UIView*)parent
|
||||
{
|
||||
if (parent.isFirstResponder) {
|
||||
return parent;
|
||||
}
|
||||
for (UIView *subView in parent.subviews) {
|
||||
id responder = [self findFirstResponder:subView];
|
||||
if (responder != nil) {
|
||||
return responder;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)willMoveToParentViewController:(UIViewController *)parent
|
||||
{
|
||||
if (parent == nil) {
|
||||
id responder = [self findFirstResponder:self.view];
|
||||
if (responder != nil) {
|
||||
_previousFirstResponder = responder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyFinishTransitioning
|
||||
{
|
||||
[_previousFirstResponder becomeFirstResponder];
|
||||
_previousFirstResponder = nil;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
self.view = _view;
|
||||
|
||||
@@ -109,22 +109,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
// add new screens in order they are placed in subviews array
|
||||
for (RNSScreenView *screen in _reactSubviews) {
|
||||
if (screen.active && ![_activeScreens containsObject:screen]) {
|
||||
[_activeScreens addObject:screen];
|
||||
[self attachScreen:screen];
|
||||
} else if (screen.active && activeScreenAdded) {
|
||||
// if we are adding new active screen, we perform remounting of all already marked as active
|
||||
// this is done to mimick the effect UINavigationController has when willMoveToWindow:nil is
|
||||
// triggered before the animation starts
|
||||
if (activeScreenAdded) {
|
||||
// if we are adding new active screen, we perform remounting of all already marked as active
|
||||
// this is done to mimick the effect UINavigationController has when willMoveToWindow:nil is
|
||||
// triggered before the animation starts
|
||||
if (activeScreenAdded) {
|
||||
for (RNSScreenView *screen in _reactSubviews) {
|
||||
if (screen.active && [_activeScreens containsObject:screen]) {
|
||||
[self detachScreen:screen];
|
||||
// disable interactions for the duration of transition
|
||||
screen.userInteractionEnabled = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// add new screens in order they are placed in subviews array
|
||||
for (RNSScreenView *screen in _reactSubviews) {
|
||||
if (screen.active) {
|
||||
[self attachScreen:screen];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we are down to one active screen it means the transitioning is over and we want to notify
|
||||
// the transition has finished
|
||||
if (activeScreenRemoved && _activeScreens.count == 1) {
|
||||
RNSScreenView *singleActiveScreen = [_activeScreens anyObject];
|
||||
// restore interactions
|
||||
singleActiveScreen.userInteractionEnabled = YES;
|
||||
[singleActiveScreen notifyFinishTransitioning];
|
||||
}
|
||||
|
||||
if ((activeScreenRemoved || activeScreenAdded) && _controller.presentedViewController == nil) {
|
||||
// if user has reachability enabled (one hand use) and the window is slided down the below
|
||||
// method will force it to slide back up as it is expected to happen with UINavController when
|
||||
|
||||
Reference in New Issue
Block a user