diff --git a/content/core/utils.md b/content/core/utils.md index 8b1fa2ad..02bfc796 100644 --- a/content/core/utils.md +++ b/content/core/utils.md @@ -87,7 +87,6 @@ const labelHierarchy: Array = Utils.getBaseClasses(new Label()) ] */ ``` -### Hiding a keyboard To hide a soft keyboard on the screen, use the [dismissKeyboard()](#dismisskeyboard) method. @@ -101,7 +100,6 @@ Utils.dismissKeyboard() ```ts const majorVersion: number = Utils.ios -``` (`iOS only`) Gets the iOS device major version. For example, for `16.0` ,it returns `16`. @@ -115,7 +113,6 @@ const isFileOrResourcePath: boolean = Utils.isFileOrResourcePath(path) Returns `true` if the specified path points to a resource or local file. ---- ### isDataURI() @@ -142,7 +139,6 @@ const escapedString: string = Utils.escapeRegexSymbols(string) ``` Escapes special regex characters (`.`, `*`, `^`, `$` and so on) in a string and returns a valid regex. - --- ### convertString() @@ -171,14 +167,10 @@ A utility function that invokes garbage collection on the JavaScript side. Utils.queueMacrotask(task: () => void) ``` -Queues the passed function to be ran as a macroTask. - ---- ### queueGC() ```ts -Utils.queueGC(delay, useThrottle) ``` - _Optional_: `delay` time, in milliseconds, to wait before garbage collection starts. @@ -186,7 +178,6 @@ Utils.queueGC(delay, useThrottle) A utility function that queues a garbage collection. Multiple calls in quick succession are debounced by default and only one gc will be executed after 900ms. ---- ### debounce() @@ -194,7 +185,6 @@ A utility function that queues a garbage collection. Multiple calls in quick suc const debouncedFn = Utils.debounce(fn, delay) debouncedFn() -``` A simple debounce utility. @@ -202,7 +192,6 @@ A simple debounce utility. - _Optional_:`delay` delays the bouncing, in milliseconds. Defaults to 300ms. --- - ### throttle() ```ts @@ -215,7 +204,6 @@ A simple throttle utility. - `fn` The function to throttle. - _Optional_:`delay` delays the throttling, in milliseconds. Defaults to 300ms. - --- ### isFontIconURI() @@ -223,7 +211,6 @@ A simple throttle utility. ```ts const isFontIconURI: boolean = Utils.isFontIconURI('font://') ``` - Returns true if the specified URI is a font icon URI. --- @@ -235,7 +222,6 @@ Utils.executeOnMainThread(fn: Function) ``` -Checks if the current thread is the main thread. If it is, calls the passed function. Otherwise, it dispatches it to the main thread. :::warning Important! @@ -252,7 +238,6 @@ Utils.executeOnUIThread(fn: Function) ``` Runs the passed function on the UI Thread. - :::warning Important! Always dispatches asynchronously to the UI thread. @@ -525,6 +510,8 @@ Hides any keyboard on the screen. --- +## Utils.android + ### getApplication() ```ts @@ -535,6 +522,19 @@ const app: android.app.Application = Utils.android.getApplication() --- +### getCurrentActivity() + +```ts +const activity: + | androidx.appcompat.app.AppCompatActivity + | android.app.Activity + | null = Utils.android.getCurrentActivity() +``` + +(`Android-only`) Gets the current foreground Android Activity if available, otherwise `null`. + +--- + ### getApplicationContext() ```ts @@ -545,6 +545,123 @@ Utils.android.getApplicationContext() --- +### getResources() + +```ts +const resources: android.content.res.Resources = Utils.android.getResources() +``` + +(`Android-only`) Gets the native Android [Resources](https://developer.android.com/reference/android/content/res/Resources) for the application. + +--- + +### getPackageName() + +```ts +const pkg: string = Utils.android.getPackageName() +``` + +(`Android-only`) Gets the application package name. + +--- + +### enableEdgeToEdge() + +```ts +function enableEdgeToEdge( + activity: androidx.appcompat.app.AppCompatActivity, + options?: { + statusBarLightColor?: Color + statusBarDarkColor?: Color + navigationBarLightColor?: Color + navigationBarDarkColor?: Color + handleDarkMode?: ( + bar: 'status' | 'navigation', + resources: android.content.res.Resources, + ) => boolean + }, +): void +``` + +Enables full edge-to-edge rendering on Android and lets you customize system UI overlay colors and behavior. + +- `activity` The current `AppCompatActivity` instance. +- _Optional_ `options` may include: + - `statusBarLightColor` Color to use for light appearance of the status bar (icons dark on light background). + - `statusBarDarkColor` Color to use for dark appearance of the status bar (icons light on dark background). + - `navigationBarLightColor` Color to use for light appearance of the navigation bar. + - `navigationBarDarkColor` Color to use for dark appearance of the navigation bar. + - `handleDarkMode` Decide whether light or dark system UI should be used for the given bar based on your own logic. Return `true` to use light appearance, `false` for dark. + +Notes: +- Works together with Page `androidOverflowEdge` and `androidOverflowInset` to control inset application/consumption. +- When insets are applied, they are added to the view's padding. + +Example: + +```ts +import { Application, Utils, Color } from '@nativescript/core' + +const activity = Utils.android.getCurrentActivity() + +Utils.android.enableEdgeToEdge(activity, { + statusBarLightColor: new Color('#FFFFFF'), + statusBarDarkColor: new Color('#000000'), + navigationBarLightColor: new Color('#FFFFFF'), + navigationBarDarkColor: new Color('#000000'), + handleDarkMode: (bar, resources) => { + // Decide per your theme; return true for light appearance + return true + }, +}) +``` + +--- + +### setDarkModeHandler() + +```ts +Utils.android.setDarkModeHandler(options?: { + activity?: androidx.appcompat.app.AppCompatActivity + handler: ( + bar: 'status' | 'navigation', + resources: android.content.res.Resources, + ) => boolean +}) +``` + +(`Android-only`) Sets a handler to decide whether the specified system bar should use light or dark appearance based on your logic. + +--- + +### setNavigationBarColor() + +```ts +Utils.android.setNavigationBarColor(options?: { + activity?: androidx.appcompat.app.AppCompatActivity + lightColor?: Color + darkColor?: Color +}) +``` + +(`Android-only`) Sets the navigation bar color for the application for light/dark appearances. + +--- + +### setStatusBarColor() + +```ts +Utils.android.setStatusBarColor(options?: { + activity?: androidx.appcompat.app.AppCompatActivity + lightColor?: Color + darkColor?: Color +}) +``` + +(`Android-only`) Sets the status bar color for the application for light/dark appearances. + +--- + ### getInputMethodManager() ```ts @@ -566,6 +683,16 @@ Utils.android.showSoftInput(nativeView) --- +### dismissSoftInput() + +```ts +Utils.android.dismissSoftInput(nativeView?) +``` + +(`Android-only`) Hides the soft input method (soft keyboard). Optionally provide a specific `android.view.View`. + +--- + ### stringArrayToStringSet() ```ts @@ -607,39 +734,50 @@ Gets the string id from a given resource name. --- -### getPaletteColor() +### getId() ```ts -const paletteColor: number = Utils.android.resources.getPaletteColor( - resourceName, - Utils.android.getApplicationContext(), -) +const viewId: number = Utils.android.resources.getId(resourceName) ``` -Gets a color from the current theme. +Gets an `id` resource by name. --- -### joinPaths() +### getResource() ```ts -const joinedPath: string = Utils.ios.joinPaths('photos', 'cat.png') +const resId: number = Utils.android.resources.getResource(name, type?) ``` -Joins the passed strings into a path. +Gets a resource identifier by name with an optional type. This sets an explicit package name under the hood. +See Android's [`Resources.getIdentifier`](https://developer.android.com/reference/android/content/res/Resources#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)). --- +### getPaletteColor() + +```ts +const paletteColor: number = Utils.android.resources.getPaletteColor( + resourceName, + Utils.android.getApplicationContext(), +) +``` + +Gets a color from the current theme. + ### getWindow() ```ts -const window: UIWindow = Utils.ios.getWindow() +const window: android.view.Window = Utils.android.getWindow() ``` -Gets the UIWindow of the app. +*Deprecated*. Use the generic `Utils.getWindow()` instead. --- +## Utils.ios + ### copyToClipboard() ```ts @@ -708,6 +846,94 @@ Create a [UIDocumentInteractionControllerDelegate](https://developer.apple.com/d --- +### getMainScreen() + +```ts +const screen: UIScreen = Utils.ios.getMainScreen() +``` + +(`iOS only`) Returns the main UIScreen. + +--- + +### isLandscape() (deprecated) + +```ts +const landscape: boolean = Utils.ios.isLandscape() +``` + +(`iOS only`) Deprecated. Use `Application.orientation` instead. + +--- + +### snapshotView() + +```ts +const image: UIImage = Utils.ios.snapshotView(view: UIView, scale: number) +``` + +(`iOS only`) Takes a snapshot image of the provided `UIView` at the desired screen `scale`. + +--- + +### applyRotateTransform() + +```ts +const result: CATransform3D = Utils.ios.applyRotateTransform( + transform: CATransform3D, + x: number, + y: number, + z: number, +) +``` + +(`iOS only`) Returns a transform rotated by the specified degrees around the X, Y and Z axes. + +--- + +### printCGRect() + +```ts +Utils.ios.printCGRect(rect: CGRect) +``` + +(`iOS only`) Debug utility to print `CGRect` values in logs (printing `CGRect` directly may appear blank otherwise). + +--- + +### copyLayerProperties() + +```ts +Utils.ios.copyLayerProperties( + view: UIView, + toView: UIView, + customProperties?: { view?: Array; layer?: Array }, +) +``` + +(`iOS only`) Copies layer-related properties from one view to another. You can provide custom property lists for `view` and `layer`. + +--- + +### animateWithSpring() + +```ts +Utils.ios.animateWithSpring(options?: { + tension?: number + friction?: number + mass?: number + delay?: number + velocity?: number + animateOptions?: UIViewAnimationOptions + animations?: () => void + completion?: (finished?: boolean) => void +}) +``` + +(`iOS only`) Animates property changes with a configurable spring effect. + +--- + ### jsArrayToNSArray() ```ts @@ -728,6 +954,18 @@ const nsArrayToJSArray: Array = nsArrayToJSArray(a: NSArray) --- +### getWindow() + +```ts +const window: UIWindow = Utils.ios.getWindow() +``` + +Gets the UIWindow of the app. + +*Deprecated*. Use the generic `Utils.getWindow()` instead. + +--- + ## API Reference(s) - [@nativescript/core/utils](https://docs.nativescript.org/api/namespace/Utils) module diff --git a/content/ui/page.md b/content/ui/page.md index 5eb18771..684e33be 100644 --- a/content/ui/page.md +++ b/content/ui/page.md @@ -267,6 +267,44 @@ Gets or sets the color of the status bar on Android devices. **Android only.** See [Color](/api/class/Color). +### androidOverflowEdge + +```ts +androidOverflowEdge: + | 'none' + | 'left' + | 'top' + | 'right' + | 'bottom' + | 'dont-apply' + | 'left-dont-consume' + | 'top-dont-consume' + | 'right-dont-consume' + | 'bottom-dont-consume' + | 'all-but-left' + | 'all-but-top' + | 'all-but-right' + | 'all-but-bottom' +``` + +Controls how Android system insets (status bar, navigation bar, cutouts) are applied and/or consumed by the Page. When insets are applied, they are added to the Page's padding. Insets propagate down the view hierarchy until consumed. Defaults to `'dont-apply'` for Pages. **Android only.** + +Options: + +| Value | Behavior | +|---|---| +| `none` | Apply and consume all inset edges | +| `left` / `top` / `right` / `bottom` | Apply and consume only the specified edge | +| `dont-apply` | Do not apply or consume any insets — triggers `androidOverflowInset` | +| `left-dont-consume` | Apply the left inset but do not consume it; all other insets are ignored | +| `top-dont-consume` | Apply the top inset but do not consume it; all other insets are ignored | +| `right-dont-consume` | Apply the right inset but do not consume it; all other insets are ignored | +| `bottom-dont-consume` | Apply the bottom inset but do not consume it; all other insets are ignored | +| `all-but-left` | Apply and consume all insets except left | +| `all-but-top` | Apply and consume all insets except top | +| `all-but-right` | Apply and consume all insets except right | +| `all-but-bottom` | Apply and consume all insets except bottom | + ### enableSwipeBackNavigation ```ts @@ -346,6 +384,72 @@ on('navigatedFrom', (args: NavigatedData) => { Emitted after the app has navigated away from the current page. +### androidOverflowInset + +```ts +on('androidOverflowInset', (args) => { + // args.inset: { top, bottom, left, right, topConsumed?, bottomConsumed?, leftConsumed?, rightConsumed? } +}) +``` + +Emitted when `androidOverflowEdge` is set to `'dont-apply'`, allowing manual handling of system insets. You can inspect and modify inset values and explicitly consume individual sides by setting the corresponding `*Consumed` flags. **Android only.** + +Example: + +```ts +page.on('androidOverflowInset', (args) => { + // Modify inset values if needed + args.inset.top += 10 + args.inset.bottom += 10 + args.inset.left += 10 + args.inset.right += 10 + + // Explicitly consume each side + args.inset.topConsumed = true + args.inset.bottomConsumed = true + args.inset.leftConsumed = true + args.inset.rightConsumed = true +}) +``` + +## Android: Edge-to-Edge tip + +::: tip Edge-to-Edge on Android +You can opt into full edge-to-edge and precisely control how system insets are handled on a per-Page basis. + +- Set `androidOverflowEdge` to choose which inset edges to apply and/or consume. Pages default to `'dont-apply'`. +- When using `'dont-apply'`, handle `androidOverflowInset` to adjust and explicitly consume sides. +- Call `Utils.android.enableEdgeToEdge(...)` to enable edge-to-edge and configure light/dark system UI overlays. + +Example: + +```ts +import { Utils } from '@nativescript/core' + +// Let the page handle insets manually +page.androidOverflowEdge = 'dont-apply' + +// Enable edge-to-edge (Android) with light/dark colors +import { Application, Color } from '@nativescript/core' +const activity = + Application.android.foregroundActivity || Application.android.startActivity +Utils.android.enableEdgeToEdge(activity, { + statusBarLightColor: new Color('#FFFFFF'), + statusBarDarkColor: new Color('#000000'), +}) + +// Optionally handle and consume insets yourself +page.on('androidOverflowInset', (args) => { + args.inset.top += 8 + args.inset.bottom += 8 + args.inset.topConsumed = true + args.inset.bottomConsumed = true +}) +``` + +See also: [enableEdgeToEdge](/core/utils#enableedgetoedge). +::: + ## Native component - Android: [`org.nativescript.widgets.GridLayout`](https://github.com/NativeScript/NativeScript/blob/master/packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/GridLayout.java)