| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 37d8d33 commit 1c40591
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1 +1,36 @@ | |||
| 1 | + import { Frame, GridLayout, Label, TabView, View } from '@nativescript/core'; | ||
| 2 | + import * as TKUnit from '../../tk-unit'; | ||
| 3 | + import * as helper from '../../ui-helper'; | ||
| 4 | + | ||
| 1 | 5 | export * from './frame-tests-common'; | |
| 6 | + | ||
| 7 | + function assertHostedBelowHeader(hosted: View) { | ||
| 8 | + const header = new Label(); | ||
| 9 | + header.text = 'Header'; | ||
| 10 | + const grid = new GridLayout(); | ||
| 11 | + grid.rows = '50, *'; | ||
| 12 | + GridLayout.setRow(hosted, 1); | ||
| 13 | + grid.addChild(header); | ||
| 14 | + grid.addChild(hosted); | ||
| 15 | + | ||
| 16 | + helper.buildUIAndRunTest(grid, () => { | ||
| 17 | + helper.waitUntilLayoutReady(hosted); | ||
| 18 | + | ||
| 19 | + const headerFrame = (header.nativeViewProtected as UIView).frame; | ||
| 20 | + const hostedFrame = (hosted.nativeViewProtected as UIView).frame; | ||
| 21 | + const container = (grid.nativeViewProtected as UIView).bounds; | ||
| 22 | + | ||
| 23 | + TKUnit.assertAreClose(hostedFrame.origin.y, headerFrame.origin.y + headerFrame.size.height, 0.5, 'top'); | ||
| 24 | + TKUnit.assertAreClose(hostedFrame.origin.y + hostedFrame.size.height, container.size.height, 0.5, 'bottom'); | ||
| 25 | + TKUnit.assertAreClose(hostedFrame.origin.x, 0, 0.5, 'left'); | ||
| 26 | + TKUnit.assertAreClose(hostedFrame.size.width, container.size.width, 0.5, 'width'); | ||
| 27 | + }); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + export function test_frame_hosted_in_layout_fills_its_cell() { | ||
| 31 | + assertHostedBelowHeader(new Frame()); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + export function test_tab_view_hosted_in_layout_fills_its_cell() { | ||
| 35 | + assertHostedBelowHeader(new TabView()); | ||
| 36 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -76,6 +76,16 @@ export namespace IOSHelper { | |||
| 76 | 76 | * view, or hides them all for `none`. No-op before iOS 26. | |
| 77 | 77 | */ | |
| 78 | 78 | export function setScrollEdgeEffect(scrollView: any /* UIScrollView */, effect: CoreTypes.ScrollEdgeEffectType): void; | |
| 79 | + /** | ||
| 80 | + * Whether the view's native view is a direct subview of its nearest NativeScript ancestor's | ||
| 81 | + * native view, rather than placed by a UIKit container controller. | ||
| 82 | + */ | ||
| 83 | + export function isHostedInView(view: View): boolean; | ||
| 84 | + /** | ||
| 85 | + * Moves the frame's edges that lie on the container's safe-area edges out to the container's | ||
| 86 | + * bounds, for controller-backed views that inset their own content. | ||
| 87 | + */ | ||
| 88 | + export function extendUnderContainerSafeArea(nativeView: any /* UIView */, frame: any /* CGRect */): any; /* CGRect */ | ||
| 79 | 89 | export function invalidateStatusBarAppearance(controller?: any /* UIViewController */, reason?: string): void; | |
| 80 | 90 | export function updateAutoAdjustScrollInsets(controller: any /* UIViewController */, owner: View): void; | |
| 81 | 91 | export function updateConstraints(controller: any /* UIViewController */, owner: View): void; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -329,6 +329,40 @@ export class IOSHelper { | |||
| 329 | 329 | return view; | |
| 330 | 330 | } | |
| 331 | 331 | ||
| 332 | + static isHostedInView(view: View): boolean { | ||
| 333 | + const container = view.nativeViewProtected?.superview; | ||
| 334 | + if (!container) { | ||
| 335 | + return false; | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + let parent = view.parent as View; | ||
| 339 | + while (parent && !parent.nativeViewProtected) { | ||
| 340 | + parent = parent.parent as View; | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + return container === parent?.nativeViewProtected; | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + static extendUnderContainerSafeArea(nativeView: UIView, frame: CGRect): CGRect { | ||
| 347 | + const container = nativeView?.superview; | ||
| 348 | + if (!container) { | ||
| 349 | + return null; | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + // Edges laid out against the container's safe area move out to its bounds; a controller's view insets its own content. | ||
| 353 | + const safeArea = container.safeAreaLayoutGuide.layoutFrame; | ||
| 354 | + const bounds = container.bounds; | ||
| 355 | + const tolerance = 0.5; | ||
| 356 | + const left = frame.origin.x <= safeArea.origin.x + tolerance ? bounds.origin.x : frame.origin.x; | ||
| 357 | + const top = frame.origin.y <= safeArea.origin.y + tolerance ? bounds.origin.y : frame.origin.y; | ||
| 358 | + const frameRight = frame.origin.x + frame.size.width; | ||
| 359 | + const frameBottom = frame.origin.y + frame.size.height; | ||
| 360 | + const right = frameRight >= safeArea.origin.x + safeArea.size.width - tolerance ? bounds.origin.x + bounds.size.width : frameRight; | ||
| 361 | + const bottom = frameBottom >= safeArea.origin.y + safeArea.size.height - tolerance ? bounds.origin.y + bounds.size.height : frameBottom; | ||
| 362 | + | ||
| 363 | + return CGRectMake(left, top, right - left, bottom - top); | ||
| 364 | + } | ||
| 365 | + | ||
| 332 | 366 | static invalidateStatusBarAppearance(controller?: UIViewController, reason = ''): void { | |
| 333 | 367 | try { | |
| 334 | 368 | if (!controller) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -361,27 +361,15 @@ export class Frame extends FrameBase { | |||
| 361 | 361 | this.setMeasuredDimension(widthAndState, heightAndState); | |
| 362 | 362 | } | |
| 363 | 363 | ||
| 364 | - public layoutNativeView(left: number, top: number, right: number, bottom: number): void { | ||
| 365 | - const nativeView = this.nativeViewProtected; | ||
| 366 | - const container = nativeView?.superview; | ||
| 367 | - if (!container) { | ||
| 368 | - return; | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - let parent = this.parent as View; | ||
| 372 | - while (parent && !parent.nativeViewProtected) { | ||
| 373 | - parent = parent.parent as View; | ||
| 374 | - } | ||
| 375 | - | ||
| 376 | - // UIKit never sizes a nested Frame; it keeps UIScreen.main bounds. | ||
| 377 | - const isNestedInView = container === parent?.nativeViewProtected; | ||
| 378 | - if (isNestedInView && !CGRectEqualToRect(nativeView.frame, container.bounds)) { | ||
| 379 | - nativeView.frame = container.bounds; | ||
| 364 | + public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { | ||
| 365 | + // UIKit lays out the controller's view inside a container controller, but not inside a NativeScript view. | ||
| 366 | + if (IOSHelper.isHostedInView(this)) { | ||
| 367 | + super._setNativeViewFrame(nativeView, frame); | ||
| 380 | 368 | } | |
| 381 | 369 | } | |
| 382 | 370 | ||
| 383 | - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { | ||
| 384 | - // | ||
| 371 | + protected applySafeAreaInsets(frame: CGRect): CGRect { | ||
| 372 | + return IOSHelper.extendUnderContainerSafeArea(this.nativeViewProtected, frame); | ||
| 385 | 373 | } | |
| 386 | 374 | ||
| 387 | 375 | // Emits an event whenever the UINavigationController shows a view controller. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -390,12 +390,15 @@ export class TabView extends TabViewBase { | |||
| 390 | 390 | return this._ios; | |
| 391 | 391 | } | |
| 392 | 392 | ||
| 393 | - public layoutNativeView(left: number, top: number, right: number, bottom: number): void { | ||
| 394 | - // | ||
| 393 | + public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { | ||
| 394 | + // UIKit lays out the controller's view inside a container controller, but not inside a NativeScript view. | ||
| 395 | + if (IOSHelper.isHostedInView(this)) { | ||
| 396 | + super._setNativeViewFrame(nativeView, frame); | ||
| 397 | + } | ||
| 395 | 398 | } | |
| 396 | 399 | ||
| 397 | - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { | ||
| 398 | - // | ||
| 400 | + protected applySafeAreaInsets(frame: CGRect): CGRect { | ||
| 401 | + return IOSHelper.extendUnderContainerSafeArea(this.nativeViewProtected, frame); | ||
| 399 | 402 | } | |
| 400 | 403 | ||
| 401 | 404 | public onSelectedIndexChanged(oldIndex: number, newIndex: number): void { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments