-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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]:iPhone X: Need to be able to control the Insets / Layout Margins #9475
Changes from 19 commits
312ee2a
0080d45
5a12013
b34604c
3b5c1a5
7f48efa
25709d8
00c0262
378c5c1
5d17368
8aa4c49
73159dc
adeaeaa
e14f1a2
967bdaf
7789988
1d9f24e
ecf5b94
e087ac7
34f9b7c
7651eca
cbc8623
179f75e
d6113d4
c5b9022
de5871c
7db933d
74eed9b
6cd1e94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hansemannn status-bar, iPhone X home-indicator & iPhone X notch are not part of safe area. Let us remove the statement from doc. Let us discuss on this. Thanks. |
||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo. Change "safe-are" to "safe-area". |
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The status-bar on iOS is 20dp (ie: Apple points), not 20px. |
||
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: | | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,10 @@ | |
- (void)updateNavBar; | ||
- (void)boot:(BOOL)timeout args:(id)args; | ||
|
||
#if IS_XCODE_9 | ||
@property (nonatomic, assign) TiViewProxy *safeAreaViewProxy; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add one tmpty line for readability. Also ensure to format everything with our clang-format |
||
@property (nonatomic) BOOL shouldExtendSafeArea; | ||
#endif | ||
@end | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,6 +145,9 @@ - (NSString *)apiName | |
|
||
- (void)dealloc | ||
{ | ||
#if IS_XCODE_9 | ||
self.safeAreaViewProxy = nil; | ||
#endif | ||
RELEASE_TO_NIL(barImageView); | ||
[super dealloc]; | ||
} | ||
|
@@ -246,7 +249,13 @@ - (BOOL)_handleClose:(id)args | |
|
||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator | ||
{ | ||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; | ||
#if IS_XCODE_9 | ||
[self performSelector:@selector(processForSafeArea) | ||
withObject:nil | ||
afterDelay:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration]]; | ||
#endif | ||
[super viewWillTransitionToSize:size | ||
withTransitionCoordinator:coordinator]; | ||
[self willChangeSize]; | ||
} | ||
|
||
|
@@ -970,6 +979,92 @@ - (void)cleanupWindowDecorations | |
[barImageView removeFromSuperview]; | ||
} | ||
} | ||
|
||
#if IS_XCODE_9 | ||
|
||
- (TiViewProxy *)safeAreaView | ||
{ | ||
return self.safeAreaViewProxy; | ||
} | ||
|
||
- (void)processForSafeArea | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be compiled out by |
||
{ | ||
// 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,10 @@ | |
#import <QuartzCore/QuartzCore.h> | ||
#import <libkern/OSAtomic.h> | ||
#import <pthread.h> | ||
#if IS_XCODE_9 | ||
#import "TiUIViewProxy.h" | ||
#import "TiUIWindowProxy.h" | ||
#endif | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Compile out for Xcode < 9 |
||
#define IGNORE_IF_NOT_OPENED \ | ||
if (!windowOpened || [self viewAttached] == NO) \ | ||
|
@@ -167,10 +171,29 @@ - (BOOL)belongsToContext:(id<TiEvaluator>)context | |
|
||
- (void)add:(id)arg | ||
{ | ||
#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) { | ||
[self add:a]; | ||
#if IS_XCODE_9 | ||
if (windowProxy.safeAreaViewProxy) { | ||
[windowProxy.safeAreaViewProxy add:a]; | ||
} else { | ||
#endif | ||
[self add:a]; | ||
#if IS_XCODE_9 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does this bracket belong to? Maybe this is more readable (untested!): // 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];
continue;
}
#endif
[self add:a];
}
return;
} |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Compile out for Xcode < 9, change the access of |
||
#endif | ||
} | ||
return; | ||
} | ||
|
@@ -185,6 +208,12 @@ - (void)add:(id)arg | |
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]]) { | ||
|
@@ -277,6 +306,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]; | ||
|
@@ -290,6 +329,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); | ||
|
||
#ifdef HYPERLOOP | ||
|
@@ -351,6 +400,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]; | ||
|
@@ -1427,7 +1486,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 | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question:
If this is set
false
, then what will this mean for a translucent status bar? Will the window's background color or image be behind the translucent status bar or not? If yes, then does the window'sheight
property include the height of the status bar then?I ask because we may want to document these details. This may matter to a developer who is doing absolute positioning via a composite layout that involves subtracting from the window height. Please see the "LayoutTest.js" sample project attached to TIMOB-24972 and try its "Absolute Position" test in the list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
false
, it will not extend the safe-area (status-bar is part of that), meaning that a translucent status-bar should receive the window-background-color and the height of the window will not be influenced by the status-bar.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so, this means that
window.height
andwindow.width
returns the safe area width height in this case, right? We should document this detail.