diff --git a/apps/app/ui-tests-app/scroll-view/main-page.ts b/apps/app/ui-tests-app/scroll-view/main-page.ts index 116a1d77d..b453762bb 100644 --- a/apps/app/ui-tests-app/scroll-view/main-page.ts +++ b/apps/app/ui-tests-app/scroll-view/main-page.ts @@ -12,5 +12,7 @@ export function pageLoaded(args: EventData) { export function loadExamples() { const examples = new Map(); examples.set("scrolling-and-sizing", "scroll-view/scrolling-and-sizing"); + examples.set("safe-area-root-element", "scroll-view/safe-area-root-element"); + examples.set("safe-area-sub-element", "scroll-view/safe-area-sub-element"); return examples; } \ No newline at end of file diff --git a/apps/app/ui-tests-app/scroll-view/safe-area-root-element.xml b/apps/app/ui-tests-app/scroll-view/safe-area-root-element.xml new file mode 100644 index 000000000..0d63dc6c6 --- /dev/null +++ b/apps/app/ui-tests-app/scroll-view/safe-area-root-element.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/app/ui-tests-app/scroll-view/safe-area-sub-element.xml b/apps/app/ui-tests-app/scroll-view/safe-area-sub-element.xml new file mode 100644 index 000000000..febf79f0e --- /dev/null +++ b/apps/app/ui-tests-app/scroll-view/safe-area-sub-element.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tns-core-modules/ui/core/view-base/view-base.d.ts b/tns-core-modules/ui/core/view-base/view-base.d.ts index c28482d6e..7cd7ee7a4 100644 --- a/tns-core-modules/ui/core/view-base/view-base.d.ts +++ b/tns-core-modules/ui/core/view-base/view-base.d.ts @@ -372,6 +372,10 @@ export abstract class ViewBase extends Observable { public _isPaddingRelative: boolean; public _styleScope: any; + /** + * @private + */ + public _automaticallyAdjustsScrollViewInsets: boolean; /** * @private */ diff --git a/tns-core-modules/ui/core/view-base/view-base.ts b/tns-core-modules/ui/core/view-base/view-base.ts index 11f4e809c..474a50ed7 100644 --- a/tns-core-modules/ui/core/view-base/view-base.ts +++ b/tns-core-modules/ui/core/view-base/view-base.ts @@ -178,7 +178,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition private _templateParent: ViewBase; private __nativeView: any; // private _disableNativeViewRecycling: boolean; - + public domNode: dnm.DOMNode; public recycleNativeView: "always" | "never" | "auto"; @@ -199,6 +199,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition public _suspendedUpdates: { [propertyName: string]: Property | CssProperty | CssAnimationProperty }; public _suspendNativeUpdatesCount: SuspendType; public _isStyleScopeHost: boolean; + public _automaticallyAdjustsScrollViewInsets: boolean; // Dynamic properties. left: Length; diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index ed668434e..7d27931f8 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -592,6 +592,8 @@ export namespace ios { export function updateAutoAdjustScrollInsets(controller: UIViewController, owner: View): void { const scrollable = isContentScrollable(controller, owner); + + owner._automaticallyAdjustsScrollViewInsets = scrollable; controller.automaticallyAdjustsScrollViewInsets = scrollable; } @@ -733,7 +735,7 @@ export namespace ios { if(!owner){ return; } - + updateAutoAdjustScrollInsets(this, owner); if (!owner.parent) { diff --git a/tns-core-modules/ui/scroll-view/scroll-view.ios.ts b/tns-core-modules/ui/scroll-view/scroll-view.ios.ts index ca68ce917..f7cfe5aa9 100644 --- a/tns-core-modules/ui/scroll-view/scroll-view.ios.ts +++ b/tns-core-modules/ui/scroll-view/scroll-view.ios.ts @@ -1,11 +1,14 @@ import { ScrollEventData } from "."; import { View, layout, ScrollViewBase, scrollBarIndicatorVisibleProperty } from "./scroll-view-common"; +import { ios as iosUtils } from "../../utils/utils"; // HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to // kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism. import * as uiUtils from "tns-core-modules/ui/utils"; export * from "./scroll-view-common"; +const majorVersion = iosUtils.MajorVersion; + class UIScrollViewDelegateImpl extends NSObject implements UIScrollViewDelegate { private _owner: WeakRef; @@ -61,7 +64,7 @@ export class ScrollView extends ScrollViewBase { this.nativeViewProtected.showsHorizontalScrollIndicator = value; } else { this.nativeViewProtected.showsVerticalScrollIndicator = value; - } + } } get horizontalOffset(): number { @@ -92,7 +95,7 @@ export class ScrollView extends ScrollViewBase { return true; } [scrollBarIndicatorVisibleProperty.setNative](value: boolean) { - this.updateScrollBarVisibility(value); + this.updateScrollBarVisibility(value); } public scrollToVerticalOffset(value: number, animated: boolean) { @@ -120,6 +123,16 @@ export class ScrollView extends ScrollViewBase { const child = this.layoutView; this._contentMeasuredWidth = this.effectiveMinWidth; this._contentMeasuredHeight = this.effectiveMinHeight; + + // `_automaticallyAdjustsScrollViewInsets` is set to true only if the first child + // of UIViewController (Page, TabView e.g) is UIScrollView (ScrollView, ListView e.g). + // On iOS 11 by default UIScrollView automatically adjusts the scroll view insets, but they s + if (majorVersion > 10 && !this.parent._automaticallyAdjustsScrollViewInsets) { + // Disable automatic adjustment of scroll view insets when ScrollView + // is not the first child of UIViewController. + this.nativeViewProtected.contentInsetAdjustmentBehavior = 2; + } + if (child) { let childSize: { measuredWidth: number; measuredHeight: number }; if (this.orientation === "vertical") { @@ -165,7 +178,7 @@ export class ScrollView extends ScrollViewBase { } public _onOrientationChanged() { - this.updateScrollBarVisibility(this.scrollBarIndicatorVisible); + this.updateScrollBarVisibility(this.scrollBarIndicatorVisible); } }