diff --git a/apps/toolbox/src/pages/image-handling.ts b/apps/toolbox/src/pages/image-handling.ts
index 528712f8b..71d1381b1 100644
--- a/apps/toolbox/src/pages/image-handling.ts
+++ b/apps/toolbox/src/pages/image-handling.ts
@@ -1,4 +1,4 @@
-import { Observable, EventData, Page, ImageSource, knownFolders, path } from '@nativescript/core';
+import { Observable, EventData, Page, ImageSource, knownFolders, path, ImageSymbolEffect } from '@nativescript/core';
import { create, ImagePickerMediaType } from '@nativescript/imagepicker';
let page: Page;
@@ -10,6 +10,32 @@ export function navigatingTo(args: EventData) {
export class DemoModel extends Observable {
addingPhoto = false;
+ symbolWiggleEffect: ImageSymbolEffect;
+ symbolBounceEffect: ImageSymbolEffect;
+ symbolBreathEffect: ImageSymbolEffect;
+ symbolRotateEffect: ImageSymbolEffect;
+
+ constructor() {
+ super();
+ if (__APPLE__) {
+ this.symbolWiggleEffect = {
+ effect: NSSymbolWiggleEffect.effect(),
+ start: true,
+ };
+ this.symbolBounceEffect = {
+ effect: NSSymbolBounceEffect.effect(),
+ start: true,
+ };
+ this.symbolBreathEffect = {
+ effect: NSSymbolBreatheEffect.effect(),
+ start: true,
+ };
+ this.symbolRotateEffect = {
+ effect: NSSymbolRotateEffect.effect(),
+ start: true,
+ };
+ }
+ }
pickImage() {
const context = create({
diff --git a/apps/toolbox/src/pages/image-handling.xml b/apps/toolbox/src/pages/image-handling.xml
index 0b67d295d..ad735e19b 100644
--- a/apps/toolbox/src/pages/image-handling.xml
+++ b/apps/toolbox/src/pages/image-handling.xml
@@ -5,9 +5,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/core/references.d.ts b/packages/core/references.d.ts
index 3f788d624..93bd89d8d 100644
--- a/packages/core/references.d.ts
+++ b/packages/core/references.d.ts
@@ -2,6 +2,7 @@
///
///
///
+///
///
///
///
diff --git a/packages/core/ui/image/image-common.ts b/packages/core/ui/image/image-common.ts
index 73bc24d30..1b22851a2 100644
--- a/packages/core/ui/image/image-common.ts
+++ b/packages/core/ui/image/image-common.ts
@@ -186,3 +186,22 @@ export const decodeWidthProperty = new Property
valueConverter: Length.parse,
});
decodeWidthProperty.register(ImageBase);
+
+/**
+ * iOS only
+ * Symbol effects: https://developer.apple.com/documentation/symbols?language=objc
+ */
+export type ImageSymbolEffect = {
+ effect?: NSSymbolEffect;
+ options?: NSSymbolEffectOptions;
+ completion?: (context: UISymbolEffectCompletionContext) => void;
+ start?: boolean;
+};
+
+/**
+ * iOS only
+ */
+export const symbolEffectProperty = new Property({
+ name: 'symbolEffect',
+});
+symbolEffectProperty.register(ImageBase);
diff --git a/packages/core/ui/image/index.d.ts b/packages/core/ui/image/index.d.ts
index d142de3b6..886fbbfca 100644
--- a/packages/core/ui/image/index.d.ts
+++ b/packages/core/ui/image/index.d.ts
@@ -6,6 +6,7 @@ import { Color } from '../../color';
import { Property, InheritedCssProperty } from '../core/properties';
import { CoreTypes } from '../../core-types';
+export type { ImageSymbolEffect } from './image-common';
/**
* Represents a class that provides functionality for loading and streching image(s).
*/
diff --git a/packages/core/ui/image/index.ios.ts b/packages/core/ui/image/index.ios.ts
index 2a3ae51c2..5eb00fbfb 100644
--- a/packages/core/ui/image/index.ios.ts
+++ b/packages/core/ui/image/index.ios.ts
@@ -1,4 +1,4 @@
-import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, srcProperty } from './image-common';
+import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, srcProperty, symbolEffectProperty, ImageSymbolEffect } from './image-common';
import { ImageSource } from '../../image-source';
import { ImageAsset } from '../../image-asset';
import { Color } from '../../color';
@@ -194,4 +194,14 @@ export class Image extends ImageBase {
[srcProperty.setNative](value: string | ImageSource | ImageAsset) {
this._createImageSourceFromSrc(value);
}
+
+ [symbolEffectProperty.setNative](value: ImageSymbolEffect) {
+ if (this.nativeViewProtected) {
+ if (value?.start) {
+ this.nativeViewProtected.addSymbolEffectOptionsAnimatedCompletion(value.effect || NSSymbolScaleEffect.effect(), value.options || NSSymbolEffectOptions.optionsWithRepeating(), true, value.completion || null);
+ } else {
+ this.nativeViewProtected.removeAllSymbolEffects();
+ }
+ }
+ }
}
diff --git a/packages/core/ui/index.ts b/packages/core/ui/index.ts
index 893eb4c33..61a226f03 100644
--- a/packages/core/ui/index.ts
+++ b/packages/core/ui/index.ts
@@ -31,7 +31,7 @@ export { GesturesObserver, TouchAction, GestureTypes, GestureStateTypes, SwipeDi
export type { GestureEventData, GestureEventDataWithState, TapGestureEventData, PanGestureEventData, PinchGestureEventData, RotationGestureEventData, SwipeGestureEventData, TouchGestureEventData, TouchAnimationOptions, VisionHoverOptions } from './gestures';
export { HtmlView } from './html-view';
-export { Image } from './image';
+export { Image, ImageSymbolEffect } from './image';
export { Cache as ImageCache } from './image-cache';
export type { DownloadError, DownloadRequest, DownloadedData } from './image-cache';
export { Label } from './label';