Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-25301] (6_3_X):iPhone X Need to be able to control the Insets / Layout Margins #9485

Merged
merged 15 commits into from
Oct 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions apidoc/Titanium/UI/Window.yml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,28 @@ properties:
since: 3.1.3
osver: {ios: {min: "7.0"}}

- name: extendSafeArea
summary: |
Specifies whether the content (subviews) of the window will render inside the safe-area or not.
Only used in iOS 11 and later.
description: |
If the value is `true`, the content (subviews) of the window will not respect the safe-area, meaning that the content
will fill the whole screen available for rendering. If the value is `false`, the content of the
window will be rendered inside the safe-area (including then status-bar, iPhone X home-indicator & iPhone X notch).

Read more about the safe-area layout-guide in the [Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/).

Note: The default value is `true`, so content will extend the safe-are for backward compatibility. In Titanium SDK 7.0.0
and later, this property will be `false` by default to automatically adjust the layout. This will be a breaking
change for windows without a navigation-bar, as the status-bar is part of the safe-area, so subviews that are positioned
relatively to the status-bar do not need to include the height of the status-bar (20px) in the margins anymore.
platforms: [iphone, ipad]
type: Boolean
default: true
since: 6.3.0
availability: creation
osver: {ios: {min: "11.0"}}

- name: fullscreen
summary: Boolean value indicating if the window is fullscreen.
description: |
Expand Down
9 changes: 8 additions & 1 deletion iphone/Classes/TiUITabProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ -(void)openWindow:(NSArray*)args
{
TiWindowProxy *window = [args objectAtIndex:0];
ENSURE_TYPE(window,TiWindowProxy);


#if IS_XCODE_9
[window processForSafeArea];
#endif

if (window == rootWindow) {
[rootWindow windowWillOpen];
[rootWindow windowDidOpen];
Expand Down Expand Up @@ -371,6 +375,9 @@ - (void)handleWillShowViewController:(UIViewController *)viewController animated
}
}
TiWindowProxy* theWindow = (TiWindowProxy*)[(TiViewController*)viewController proxy];
#if IS_XCODE_9
[theWindow processForSafeArea];
#endif
if (theWindow == rootWindow) {
//This is probably too late for the root view controller.
//Figure out how to call open before this callback
Expand Down
4 changes: 4 additions & 0 deletions iphone/Classes/TiUIWindowProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
-(void)updateNavBar;
-(void)boot:(BOOL)timeout args:(id)args;

#if IS_XCODE_9
@property (nonatomic, assign) TiViewProxy *safeAreaViewProxy;
@property (nonatomic) BOOL shouldExtendSafeArea;
#endif
@end

#endif
103 changes: 99 additions & 4 deletions iphone/Classes/TiUIWindowProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,11 @@ -(NSString*)apiName

-(void)dealloc
{
RELEASE_TO_NIL(barImageView);
[super dealloc];
#if IS_XCODE_9
self.safeAreaViewProxy = nil;
#endif
RELEASE_TO_NIL(barImageView);
[super dealloc];
}

-(void)boot:(BOOL)timeout args:args
Expand Down Expand Up @@ -256,8 +259,14 @@ -(BOOL)_handleClose:(id)args

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self willChangeSize];
#if IS_XCODE_9
[self performSelector:@selector(processForSafeArea)
withObject:nil
afterDelay:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration]];
#endif
[super viewWillTransitionToSize:size
withTransitionCoordinator:coordinator];
[self willChangeSize];
}

- (void)systemLayoutFittingSizeDidChangeForChildContentContainer:(id <UIContentContainer>)container
Expand Down Expand Up @@ -977,6 +986,92 @@ -(void)cleanupWindowDecorations
[barImageView removeFromSuperview];
}
}

#if IS_XCODE_9

- (TiViewProxy *)safeAreaView
{
return self.safeAreaViewProxy;
}

- (void)processForSafeArea
{
// TO DO : Refactor this method
if (self.shouldExtendSafeArea || ![TiUtils isIOS11OrGreater]) {
return;
}
float left = 0.0;
float right = 0.0;
float top = 0.0;
float bottom = 0.0;
UIViewController<TiControllerContainment> *topContainerController = [[[TiApp app] controller] topContainerController];
UIEdgeInsets safeAreaInset = [[topContainerController hostingView] safeAreaInsets];
if (self.tabGroup) {
TiWindowProxy *windowProxy = nil;
if ([self.tabGroup isKindOfClass:[TiWindowProxy class]]) {
windowProxy = (TiWindowProxy *)self.tabGroup;
}
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (!UIInterfaceOrientationIsPortrait(orientation)) {
if (windowProxy.isMasterWindow) {
left = safeAreaInset.left;
} else if (windowProxy.isDetailWindow) {
right = safeAreaInset.right;
} else {
left = safeAreaInset.left;
right = safeAreaInset.right;
}
}
} else if (self.tab) {
TiWindowProxy *windowProxy = nil;
if ([self.tab isKindOfClass:[TiWindowProxy class]]) {
windowProxy = (TiWindowProxy *)self.tab;
}
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (!UIInterfaceOrientationIsPortrait(orientation)) {
if (windowProxy.isMasterWindow) {
left = safeAreaInset.left;
} else if (windowProxy.isDetailWindow) {
right = safeAreaInset.right;
} else {
left = safeAreaInset.left;
right = safeAreaInset.right;
}
}
bottom = safeAreaInset.bottom;
} else {
if (self.isMasterWindow) {
left = safeAreaInset.left;
} else if (self.isDetailWindow) {
right = safeAreaInset.right;
} else {
left = safeAreaInset.left;
right = safeAreaInset.right;
}
bottom = safeAreaInset.bottom;
top = safeAreaInset.top;
}
TiViewProxy *safeAreaProxy = [self safeAreaViewProxy];
float oldTop = [[safeAreaProxy valueForKey:@"top"] floatValue];
float oldLeft = [[safeAreaProxy valueForKey:@"left"] floatValue];
float oldRight = [[safeAreaProxy valueForKey:@"right"] floatValue];
float oldBottom = [[safeAreaProxy valueForKey:@"bottom"] floatValue];

if (oldTop != top) {
[safeAreaProxy setTop:NUMFLOAT(top)];
}
if (oldBottom != bottom) {
[safeAreaProxy setBottom:NUMFLOAT(bottom)];
}
if (oldLeft != left) {
[safeAreaProxy setLeft:NUMFLOAT(left)];
}
if (oldRight != right) {
[safeAreaProxy setRight:NUMFLOAT(right)];
}
}
#endif

@end

#endif
3 changes: 3 additions & 0 deletions iphone/Classes/TiUIiOSNavWindowProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ - (void)navigationController:(UINavigationController *)navigationController will
}
}
TiWindowProxy* theWindow = (TiWindowProxy*)[(TiViewController*)viewController proxy];
#if IS_XCODE_9
[theWindow processForSafeArea];
#endif
if ((theWindow != rootWindow) && [theWindow opening]) {
[theWindow windowWillOpen];
[theWindow windowDidOpen];
Expand Down
13 changes: 12 additions & 1 deletion iphone/Classes/TiUIiOSSplitWindow.m
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ -(void)setMasterView_:(id)args
}
RELEASE_TO_NIL(masterProxy);
masterProxy = [args retain];

#if IS_XCODE_9
TiWindowProxy *masterWindowProxy = (TiWindowProxy *)masterProxy;
masterWindowProxy.isMasterWindow = YES;
#endif

if (viewsInitialized) {
[self initProxy:masterProxy withWrapper:masterViewWrapper];
}
Expand All @@ -268,7 +274,12 @@ -(void)setDetailView_:(id)args
}
RELEASE_TO_NIL(detailProxy);
detailProxy = [args retain];


#if IS_XCODE_9
TiWindowProxy *detailWindowProxy = (TiWindowProxy *)detailProxy;
detailWindowProxy.isDetailWindow = YES;
#endif

if (viewsInitialized) {
[self initProxy:detailProxy withWrapper:detailViewWrapper];
}
Expand Down
5 changes: 4 additions & 1 deletion iphone/Classes/TiViewProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ enum
int vzIndex;
BOOL hidden; //This is the boolean version of ![TiUtils boolValue:visible def:yes]
//And has nothing to do with whether or not it's onscreen or

#if IS_XCODE_9
BOOL safeAreaProxyAdded;
#endif

#pragma mark Parent/Children relationships
TiViewProxy *parent;
pthread_rwlock_t childrenLock;
Expand Down
108 changes: 99 additions & 9 deletions iphone/Classes/TiViewProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#import <QuartzCore/QuartzCore.h>
#import <libkern/OSAtomic.h>
#import <pthread.h>
#if IS_XCODE_9
#import "TiUIViewProxy.h"
#import "TiUIWindowProxy.h"
#endif


#define IGNORE_IF_NOT_OPENED if (!windowOpened||[self viewAttached]==NO) return;
Expand Down Expand Up @@ -169,15 +173,32 @@ -(BOOL) belongsToContext:(id<TiEvaluator>) context

-(void)add:(id)arg
{
// allow either an array of arrays or an array of single proxy
if ([arg isKindOfClass:[NSArray class]])
{
for (id a in arg)
{
[self add:a];
}
return;
}
#if IS_XCODE_9
TiUIWindowProxy *windowProxy = nil;
if ([self isKindOfClass:[TiUIWindowProxy class]] && [TiUtils isIOS11OrGreater]) {
windowProxy = (TiUIWindowProxy *)self;
if (arg == windowProxy.safeAreaViewProxy) {
// If adding the safeAreaViewProxy, it need to be add on window.
windowProxy = nil;
}
}
#endif

// allow either an array of arrays or an array of single proxy
if ([arg isKindOfClass:[NSArray class]]) {
for (id a in arg) {
#if IS_XCODE_9
if (windowProxy.safeAreaViewProxy) {
[windowProxy.safeAreaViewProxy add:a];
} else {
#endif
[self add:a];
#if IS_XCODE_9
}
#endif
}
return;
}

int position = -1;
TiViewProxy *childView = nil;
Expand All @@ -188,6 +209,12 @@ -(void)add:(id)arg
if (nativeObjSel == nil) nativeObjSel = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"native", @"Object"]);
#endif
if([arg isKindOfClass:[NSDictionary class]]) {
#if IS_XCODE_9
if (windowProxy.safeAreaViewProxy) {
[windowProxy.safeAreaViewProxy add:arg];
return;
}
#endif
childView = [arg objectForKey:@"view"];
position = [TiUtils intValue:[arg objectForKey:@"position"] def:-1];
} else if([arg isKindOfClass:[TiViewProxy class]]) {
Expand Down Expand Up @@ -277,6 +304,16 @@ -(void)insertAt:(id)args

-(void)replaceAt:(id)args
{
#if IS_XCODE_9
if ([self isKindOfClass:[TiUIWindowProxy class]] && [TiUtils isIOS11OrGreater]) {
TiUIWindowProxy *windowProxy = (TiUIWindowProxy *)self;
if (windowProxy.safeAreaViewProxy) {
[windowProxy.safeAreaViewProxy replaceAt:args];
return;
}
}
#endif

ENSURE_SINGLE_ARG(args, NSDictionary);
NSInteger position = [TiUtils intValue:[args objectForKey:@"position"] def:-1];
NSArray *childrenArray = [self children];
Expand All @@ -290,6 +327,16 @@ -(void)replaceAt:(id)args

-(void)remove:(id)arg
{
#if IS_XCODE_9
if ([self isKindOfClass:[TiUIWindowProxy class]] && [TiUtils isIOS11OrGreater]) {
TiUIWindowProxy *windowProxy = (TiUIWindowProxy *)self;
if (windowProxy.safeAreaViewProxy) {
[windowProxy.safeAreaViewProxy remove:arg];
return;
}
}
#endif

ENSURE_UI_THREAD_1_ARG(arg);


Expand Down Expand Up @@ -351,6 +398,16 @@ -(void)remove:(id)arg

-(void)removeAllChildren:(id)arg
{
#if IS_XCODE_9
if ([self isKindOfClass:[TiUIWindowProxy class]] && [TiUtils isIOS11OrGreater]) {
TiUIWindowProxy *windowProxy = (TiUIWindowProxy *)self;
if (windowProxy.safeAreaViewProxy) {
[windowProxy.safeAreaViewProxy removeAllChildren:arg];
return;
}
}
#endif

ENSURE_UI_THREAD_1_ARG(arg);
pthread_rwlock_wrlock(&childrenLock);
NSMutableArray* childrenCopy = [children mutableCopy];
Expand Down Expand Up @@ -1502,8 +1559,41 @@ -(void)_initWithProperties:(NSDictionary*)properties
allowLayoutUpdate = YES;
[self processTempProperties:nil];
allowLayoutUpdate = NO;

#if IS_XCODE_9
[self createSafeAreaViewProxyForWindowProperties:properties];
#endif
}

#if IS_XCODE_9
- (void)createSafeAreaViewProxyForWindowProperties:(NSDictionary *)properties
{
if ([self isKindOfClass:[TiUIWindowProxy class]] && [TiUtils isIOS11OrGreater]) {
/*
Added a transparent safeAreaViewProxy above window for safe area layouts if shouldExtendSafeArea is false. All views added on window will be added on safeAreaViewProxy. Layouts of safeAreaViewProxy is getting modified wherever required.
*/
TiUIWindowProxy *windowProxy = (TiUIWindowProxy *)self;
windowProxy.shouldExtendSafeArea = [TiUtils boolValue:[self valueForUndefinedKey:@"extendSafeArea"] def:YES];
if (!windowProxy.safeAreaViewProxy && !windowProxy.shouldExtendSafeArea) {
NSMutableDictionary *safeAreaProperties = [NSMutableDictionary dictionary];

id layout = [self valueForUndefinedKey:@"layout"];
if (layout) {
safeAreaProperties[@"layout"] = layout;
}

id horizontalWrap = [self valueForUndefinedKey:@"horizontalWrap"];
if (horizontalWrap) {
safeAreaProperties[@"horizontalWrap"] = horizontalWrap;
}

windowProxy.safeAreaViewProxy = [[[TiUIViewProxy alloc] _initWithPageContext:[self pageContext] args:@[safeAreaProperties]] autorelease];
[windowProxy processForSafeArea];
[self add:windowProxy.safeAreaViewProxy];
}
}
}
#endif

-(void)dealloc
{
Expand Down