UNPKG

43.3 kBJavaScriptView Raw
1// Requires
2import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty } from './view-common';
3import { hiddenProperty } from '../view-base';
4import { Trace } from '../../../trace';
5import { layout, ios as iosUtils, SDK_VERSION } from '../../../utils';
6import { IOSHelper } from './view-helper';
7import { ios as iosBackground } from '../../styling/background';
8import { perspectiveProperty, visibilityProperty, opacityProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty } from '../../styling/style-properties';
9import { profile } from '../../../profiling';
10import { accessibilityEnabledProperty, accessibilityHiddenProperty, accessibilityHintProperty, accessibilityIdentifierProperty, accessibilityLabelProperty, accessibilityLanguageProperty, accessibilityLiveRegionProperty, accessibilityMediaSessionProperty, accessibilityRoleProperty, accessibilityStateProperty, accessibilityValueProperty, accessibilityIgnoresInvertColorsProperty } from '../../../accessibility/accessibility-properties';
11import { IOSPostAccessibilityNotificationType, isAccessibilityServiceEnabled, updateAccessibilityProperties } from '../../../accessibility';
12import { CoreTypes } from '../../../core-types';
13import { SharedTransition } from '../../transition/shared-transition';
14export * from './view-common';
15// helpers (these are okay re-exported here)
16export * from './view-helper';
17// This one can eventually be cleaned up but causes issues with a lot of ui-suite plugins in particular if not exported here
18export * from '../properties';
19const PFLAG_FORCE_LAYOUT = 1;
20const PFLAG_MEASURED_DIMENSION_SET = 1 << 1;
21const PFLAG_LAYOUT_REQUIRED = 1 << 2;
22export class View extends ViewCommon {
23 constructor() {
24 super(...arguments);
25 this._isLaidOut = false;
26 this._hasTransform = false;
27 this._hasPendingTransform = false;
28 this._privateFlags = PFLAG_LAYOUT_REQUIRED | PFLAG_FORCE_LAYOUT;
29 this._suspendCATransaction = false;
30 }
31 get isLayoutRequired() {
32 return (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
33 }
34 get isLayoutRequested() {
35 return (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
36 }
37 disposeNativeView() {
38 super.disposeNativeView();
39 this._cachedFrame = null;
40 this._isLaidOut = false;
41 this._hasTransform = false;
42 this._hasPendingTransform = false;
43 }
44 requestLayout() {
45 this._privateFlags |= PFLAG_FORCE_LAYOUT;
46 super.requestLayout();
47 const nativeView = this.nativeViewProtected;
48 if (nativeView && nativeView.setNeedsLayout) {
49 nativeView.setNeedsLayout();
50 }
51 if (this.viewController && this.viewController.view !== nativeView) {
52 this.viewController.view.setNeedsLayout();
53 }
54 }
55 measure(widthMeasureSpec, heightMeasureSpec) {
56 const measureSpecsChanged = this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
57 const forceLayout = (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
58 if (this.nativeViewProtected && (forceLayout || measureSpecsChanged)) {
59 // first clears the measured dimension flag
60 this._privateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
61 // measure ourselves, this should set the measured dimension flag back
62 this.onMeasure(widthMeasureSpec, heightMeasureSpec);
63 this._privateFlags |= PFLAG_LAYOUT_REQUIRED;
64 // flag not set, setMeasuredDimension() was not invoked, we trace
65 // the exception to warn the developer
66 if ((this._privateFlags & PFLAG_MEASURED_DIMENSION_SET) !== PFLAG_MEASURED_DIMENSION_SET) {
67 if (Trace.isEnabled()) {
68 Trace.write('onMeasure() did not set the measured dimension by calling setMeasuredDimension() ' + this, Trace.categories.Layout, Trace.messageType.error);
69 }
70 }
71 }
72 }
73 layout(left, top, right, bottom, setFrame = true) {
74 const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
75 if (setFrame) {
76 this.layoutNativeView(left, top, right, bottom);
77 }
78 const needsLayout = boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
79 if (needsLayout) {
80 let position = { left, top, right, bottom };
81 if (this.nativeViewProtected && SDK_VERSION > 10) {
82 // on iOS 11+ it is possible to have a changed layout frame due to safe area insets
83 // get the frame and adjust the position, so that onLayout works correctly
84 const frame = this.nativeViewProtected.frame;
85 position = IOSHelper.getPositionFromFrame(frame);
86 }
87 this.onLayout(position.left, position.top, position.right, position.bottom);
88 this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
89 }
90 this.updateBackground(sizeChanged, needsLayout);
91 if (this._hasPendingTransform) {
92 this.updateNativeTransform();
93 this._hasPendingTransform = false;
94 }
95 this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
96 }
97 updateBackground(sizeChanged, needsLayout) {
98 if (sizeChanged) {
99 this._onSizeChanged();
100 }
101 else if (this._nativeBackgroundState === 'invalid') {
102 const background = this.style.backgroundInternal;
103 this._redrawNativeBackground(background);
104 }
105 else {
106 // Update layers that don't belong to view's layer (e.g. shadow layers)
107 if (needsLayout) {
108 this.layoutOuterShadows();
109 }
110 }
111 }
112 layoutOuterShadows() {
113 const nativeView = this.nativeViewProtected;
114 if (nativeView?.outerShadowContainerLayer) {
115 CATransaction.setDisableActions(true);
116 nativeView.outerShadowContainerLayer.bounds = nativeView.bounds;
117 nativeView.outerShadowContainerLayer.position = nativeView.center;
118 CATransaction.setDisableActions(false);
119 }
120 }
121 setMeasuredDimension(measuredWidth, measuredHeight) {
122 super.setMeasuredDimension(measuredWidth, measuredHeight);
123 this._privateFlags |= PFLAG_MEASURED_DIMENSION_SET;
124 }
125 onMeasure(widthMeasureSpec, heightMeasureSpec) {
126 const view = this.nativeViewProtected;
127 const width = layout.getMeasureSpecSize(widthMeasureSpec);
128 const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
129 const height = layout.getMeasureSpecSize(heightMeasureSpec);
130 const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
131 let nativeWidth = 0;
132 let nativeHeight = 0;
133 if (view) {
134 const nativeSize = layout.measureNativeView(view, width, widthMode, height, heightMode);
135 nativeWidth = nativeSize.width;
136 nativeHeight = nativeSize.height;
137 }
138 const measureWidth = Math.max(nativeWidth, this.effectiveMinWidth);
139 const measureHeight = Math.max(nativeHeight, this.effectiveMinHeight);
140 const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0);
141 const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0);
142 this.setMeasuredDimension(widthAndState, heightAndState);
143 }
144 onLayout(left, top, right, bottom) {
145 //
146 }
147 _setNativeViewFrame(nativeView, frame) {
148 const oldFrame = this._cachedFrame || nativeView.frame;
149 if (!CGRectEqualToRect(oldFrame, frame)) {
150 if (Trace.isEnabled()) {
151 Trace.write(this + ' :_setNativeViewFrame: ' + JSON.stringify(IOSHelper.getPositionFromFrame(frame)), Trace.categories.Layout);
152 }
153 this._cachedFrame = frame;
154 let adjustedFrame = null;
155 let transform = null;
156 if (this._hasTransform) {
157 // Always set identity transform before setting frame;
158 transform = nativeView.layer.transform;
159 nativeView.layer.transform = CATransform3DIdentity;
160 nativeView.frame = frame;
161 }
162 else {
163 nativeView.frame = frame;
164 }
165 adjustedFrame = this.applySafeAreaInsets(frame);
166 if (adjustedFrame) {
167 nativeView.frame = adjustedFrame;
168 }
169 if (this._hasTransform) {
170 // re-apply the transform after the frame is adjusted
171 nativeView.layer.transform = transform;
172 }
173 const boundsOrigin = nativeView.bounds.origin;
174 const boundsFrame = adjustedFrame || frame;
175 nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, boundsFrame.size.width, boundsFrame.size.height);
176 nativeView.layoutIfNeeded();
177 this._raiseLayoutChangedEvent();
178 this._isLaidOut = true;
179 }
180 else if (!this._isLaidOut) {
181 // Rects could be equal on the first layout and an event should be raised.
182 this._raiseLayoutChangedEvent();
183 // But make sure event is raised only once if rects are equal on the first layout as
184 // this method is called twice with equal rects in landscape mode (vs only once in portrait)
185 this._isLaidOut = true;
186 }
187 }
188 get isLayoutValid() {
189 if (this.nativeViewProtected) {
190 return this._isLayoutValid;
191 }
192 return false;
193 }
194 layoutNativeView(left, top, right, bottom) {
195 if (!this.nativeViewProtected) {
196 return;
197 }
198 const nativeView = this.nativeViewProtected;
199 const frame = IOSHelper.getFrameFromPosition({
200 left,
201 top,
202 right,
203 bottom,
204 });
205 this._setNativeViewFrame(nativeView, frame);
206 }
207 _layoutParent() {
208 if (this.nativeViewProtected) {
209 const frame = this.nativeViewProtected.frame;
210 const origin = frame.origin;
211 const size = frame.size;
212 const left = layout.toDevicePixels(origin.x);
213 const top = layout.toDevicePixels(origin.y);
214 const width = layout.toDevicePixels(size.width);
215 const height = layout.toDevicePixels(size.height);
216 this._setLayoutFlags(left, top, width + left, height + top);
217 }
218 super._layoutParent();
219 }
220 _setLayoutFlags(left, top, right, bottom) {
221 const width = right - left;
222 const height = bottom - top;
223 const widthSpec = layout.makeMeasureSpec(width, layout.EXACTLY);
224 const heightSpec = layout.makeMeasureSpec(height, layout.EXACTLY);
225 this._setCurrentMeasureSpecs(widthSpec, heightSpec);
226 this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
227 this.setMeasuredDimension(width, height);
228 const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
229 this.updateBackground(sizeChanged, boundsChanged);
230 this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
231 }
232 focus() {
233 if (this.ios) {
234 return this.ios.becomeFirstResponder();
235 }
236 return false;
237 }
238 applySafeAreaInsets(frame) {
239 if (!__VISIONOS__ && SDK_VERSION <= 10) {
240 return null;
241 }
242 if (this.iosIgnoreSafeArea) {
243 return frame;
244 }
245 if (!this.iosOverflowSafeArea || !this.iosOverflowSafeAreaEnabled) {
246 return IOSHelper.shrinkToSafeArea(this, frame);
247 }
248 else if (this.nativeViewProtected && this.nativeViewProtected.window) {
249 return IOSHelper.expandBeyondSafeArea(this, frame);
250 }
251 return null;
252 }
253 getSafeAreaInsets() {
254 const safeAreaInsets = this.nativeViewProtected && this.nativeViewProtected.safeAreaInsets;
255 const insets = { left: 0, top: 0, right: 0, bottom: 0 };
256 if (this.iosIgnoreSafeArea) {
257 return insets;
258 }
259 if (safeAreaInsets) {
260 insets.left = layout.round(layout.toDevicePixels(safeAreaInsets.left));
261 insets.top = layout.round(layout.toDevicePixels(safeAreaInsets.top));
262 insets.right = layout.round(layout.toDevicePixels(safeAreaInsets.right));
263 insets.bottom = layout.round(layout.toDevicePixels(safeAreaInsets.bottom));
264 }
265 return insets;
266 }
267 getLocationInWindow() {
268 if (!this.nativeViewProtected || !this.nativeViewProtected.window) {
269 return undefined;
270 }
271 const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
272 return {
273 x: pointInWindow.x,
274 y: pointInWindow.y,
275 };
276 }
277 getLocationOnScreen() {
278 if (!this.nativeViewProtected || !this.nativeViewProtected.window) {
279 return undefined;
280 }
281 const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
282 const pointOnScreen = this.nativeViewProtected.window.convertPointToWindow(pointInWindow, null);
283 return {
284 x: pointOnScreen.x,
285 y: pointOnScreen.y,
286 };
287 }
288 getLocationRelativeTo(otherView) {
289 if (!this.nativeViewProtected || !this.nativeViewProtected.window || !otherView.nativeViewProtected || !otherView.nativeViewProtected.window || this.nativeViewProtected.window !== otherView.nativeViewProtected.window) {
290 return undefined;
291 }
292 const myPointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
293 const otherPointInWindow = otherView.nativeViewProtected.convertPointToView(otherView.nativeViewProtected.bounds.origin, null);
294 return {
295 x: myPointInWindow.x - otherPointInWindow.x,
296 y: myPointInWindow.y - otherPointInWindow.y,
297 };
298 }
299 _onSizeChanged() {
300 const nativeView = this.nativeViewProtected;
301 if (!nativeView) {
302 return;
303 }
304 const background = this.style.backgroundInternal;
305 const backgroundDependsOnSize = (background.image && background.image !== 'none') || background.clipPath || !background.hasUniformBorder() || background.hasBorderRadius() || background.hasBoxShadow();
306 if (this._nativeBackgroundState === 'invalid' || (this._nativeBackgroundState === 'drawn' && backgroundDependsOnSize)) {
307 this._redrawNativeBackground(background);
308 }
309 }
310 updateNativeTransform() {
311 if (!this.isLayoutValid) {
312 this._hasPendingTransform = true;
313 return;
314 }
315 const scaleX = this.scaleX || 1e-6;
316 const scaleY = this.scaleY || 1e-6;
317 const perspective = this.perspective || 300;
318 const nativeView = this.nativeViewProtected;
319 let transform = new CATransform3D(CATransform3DIdentity);
320 // Only set perspective if there is 3D rotation
321 if (this.rotateX || this.rotateY) {
322 transform.m34 = -1 / perspective;
323 }
324 transform = CATransform3DTranslate(transform, this.translateX, this.translateY, 0);
325 transform = iosUtils.applyRotateTransform(transform, this.rotateX, this.rotateY, this.rotate);
326 transform = CATransform3DScale(transform, scaleX, scaleY, 1);
327 const needsTransform = !CATransform3DEqualToTransform(this.nativeViewProtected.layer.transform, transform) || (nativeView.outerShadowContainerLayer && !CATransform3DEqualToTransform(nativeView.outerShadowContainerLayer.transform, transform));
328 if (needsTransform) {
329 const updateSuspended = this._isPresentationLayerUpdateSuspended();
330 if (!updateSuspended) {
331 CATransaction.begin();
332 }
333 // Disable CALayer animatable property changes
334 CATransaction.setDisableActions(true);
335 this.nativeViewProtected.layer.transform = transform;
336 if (nativeView.outerShadowContainerLayer) {
337 nativeView.outerShadowContainerLayer.transform = transform;
338 }
339 this._hasTransform = this.nativeViewProtected && !CATransform3DEqualToTransform(this.nativeViewProtected.transform3D, CATransform3DIdentity);
340 CATransaction.setDisableActions(false);
341 if (!updateSuspended) {
342 CATransaction.commit();
343 }
344 }
345 }
346 updateOriginPoint(originX, originY) {
347 const nativeView = this.nativeViewProtected;
348 const newPoint = CGPointMake(originX, originY);
349 // Disable CALayer animatable property changes
350 CATransaction.setDisableActions(true);
351 nativeView.layer.anchorPoint = newPoint;
352 // Bounds have to be recalculated after anchor point update
353 if (this._cachedFrame) {
354 const frame = this._cachedFrame;
355 this._cachedFrame = null;
356 this._setNativeViewFrame(nativeView, frame);
357 }
358 // Make sure new origin also applies to outer shadow layers
359 if (nativeView.outerShadowContainerLayer) {
360 // This is the new frame after view origin point update
361 const frame = nativeView.frame;
362 nativeView.outerShadowContainerLayer.anchorPoint = newPoint;
363 nativeView.outerShadowContainerLayer.position = CGPointMake(frame.origin.x + frame.size.width * originX, frame.origin.y + frame.size.height * originY);
364 }
365 CATransaction.setDisableActions(false);
366 }
367 // By default we update the view's presentation layer when setting backgroundColor and opacity properties.
368 // This is done by calling CATransaction begin and commit methods.
369 // This action should be disabled when updating those properties during an animation.
370 _suspendPresentationLayerUpdates() {
371 this._suspendCATransaction = true;
372 }
373 _resumePresentationLayerUpdates() {
374 this._suspendCATransaction = false;
375 }
376 _isPresentationLayerUpdateSuspended() {
377 return this._suspendCATransaction || this._suspendNativeUpdatesCount > 0;
378 }
379 _showNativeModalView(parent, options) {
380 const parentWithController = IOSHelper.getParentWithViewController(parent);
381 if (!parentWithController) {
382 Trace.write(`Could not find parent with viewController for ${parent} while showing modal view.`, Trace.categories.ViewHierarchy, Trace.messageType.error);
383 return;
384 }
385 const parentController = parentWithController.viewController;
386 if (parentController.presentedViewController) {
387 Trace.write('Parent is already presenting view controller. Close the current modal page before showing another one!', Trace.categories.ViewHierarchy, Trace.messageType.error);
388 return;
389 }
390 if (!parentController.view || !parentController.view.window) {
391 Trace.write('Parent page is not part of the window hierarchy.', Trace.categories.ViewHierarchy, Trace.messageType.error);
392 return;
393 }
394 this._setupAsRootView({});
395 super._showNativeModalView(parentWithController, options);
396 let controller = this.viewController;
397 if (!controller) {
398 const nativeView = this.ios || this.nativeViewProtected;
399 controller = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(this));
400 if (nativeView instanceof UIView) {
401 controller.view.addSubview(nativeView);
402 }
403 this.viewController = controller;
404 }
405 if (options.transition) {
406 controller.modalPresentationStyle = 4 /* UIModalPresentationStyle.Custom */;
407 if (options.transition.instance) {
408 this._transitioningDelegate = UIViewControllerTransitioningDelegateImpl.initWithOwner(new WeakRef(options.transition.instance));
409 controller.transitioningDelegate = this._transitioningDelegate;
410 this.transitionId = options.transition.instance.id;
411 const transitionState = SharedTransition.getState(options.transition.instance.id);
412 if (transitionState?.interactive?.dismiss) {
413 // interactive transitions via gestures
414 // TODO - these could be typed as: boolean | (view: View) => void
415 // to allow users to define their own custom gesture dismissals
416 options.transition.instance.setupInteractiveGesture(this._closeModalCallback.bind(this), this);
417 }
418 }
419 }
420 else if (options.fullscreen) {
421 controller.modalPresentationStyle = 0 /* UIModalPresentationStyle.FullScreen */;
422 }
423 else {
424 controller.modalPresentationStyle = 2 /* UIModalPresentationStyle.FormSheet */;
425 //check whether both height and width is provided and are positive numbers
426 // set it has prefered content size to the controller presenting the dialog
427 if (options.ios && options.ios.width > 0 && options.ios.height > 0) {
428 controller.preferredContentSize = CGSizeMake(options.ios.width, options.ios.height);
429 }
430 else {
431 //use CSS & attribute width & height if option is not provided
432 const handler = () => {
433 if (this.viewController) {
434 const w = (this.width || this.style.width);
435 const h = (this.height || this.style.height);
436 //TODO: only numeric value is supported, percentage value is not supported like Android
437 if (w > 0 && h > 0) {
438 this.viewController.preferredContentSize = CGSizeMake(w, h);
439 }
440 }
441 this.off(View.loadedEvent, handler);
442 };
443 this.on(View.loadedEvent, handler);
444 }
445 }
446 if (options.ios && options.ios.presentationStyle) {
447 const presentationStyle = options.ios.presentationStyle;
448 controller.modalPresentationStyle = presentationStyle;
449 if (presentationStyle === 7 /* UIModalPresentationStyle.Popover */) {
450 this._setupPopoverControllerDelegate(controller, parent);
451 }
452 }
453 const cancelable = options.cancelable !== undefined ? !!options.cancelable : true;
454 if (SDK_VERSION >= 13) {
455 if (cancelable) {
456 // Listen for dismiss modal callback.
457 this._setupAdaptiveControllerDelegate(controller);
458 }
459 else {
460 // Prevent users from dismissing the modal.
461 controller.modalInPresentation = true;
462 }
463 }
464 this.horizontalAlignment = 'stretch';
465 this.verticalAlignment = 'stretch';
466 this._raiseShowingModallyEvent();
467 const animated = options.animated === undefined ? true : !!options.animated;
468 if (!this._modalAnimatedOptions) {
469 // track the user's animated options to use upon close as well
470 this._modalAnimatedOptions = [];
471 }
472 this._modalAnimatedOptions.push(animated);
473 // TODO: a11y
474 // controller.accessibilityViewIsModal = true;
475 // controller.accessibilityPerformEscape = () => {
476 // console.log('accessibilityPerformEscape!!')
477 // return true;
478 // }
479 parentController.presentViewControllerAnimatedCompletion(controller, animated, null);
480 const transitionCoordinator = parentController.transitionCoordinator;
481 if (transitionCoordinator) {
482 transitionCoordinator.animateAlongsideTransitionCompletion(null, () => {
483 setTimeout(() => {
484 // ensure raised on main queue
485 this._raiseShownModallyEvent();
486 });
487 });
488 }
489 else {
490 // Apparently iOS 9+ stops all transitions and animations upon application suspend and transitionCoordinator becomes null here in this case.
491 // Since we are not waiting for any transition to complete, i.e. transitionCoordinator is null, we can directly raise our shownModally event.
492 // Take a look at https://github.com/NativeScript/NativeScript/issues/2173 for more info and a sample project.
493 this._raiseShownModallyEvent();
494 }
495 controller = null;
496 }
497 _hideNativeModalView(parent, whenClosedCallback) {
498 if (!parent || !parent.viewController) {
499 Trace.error('Trying to hide modal view but no parent with viewController specified.');
500 return;
501 }
502 // modal view has already been closed by UI, probably as a popover
503 if (!parent.viewController.presentedViewController) {
504 whenClosedCallback();
505 return;
506 }
507 const parentController = parent.viewController;
508 let animated = true;
509 if (this._modalAnimatedOptions?.length) {
510 animated = this._modalAnimatedOptions.slice(-1)[0];
511 }
512 parentController.dismissViewControllerAnimatedCompletion(animated, () => {
513 const transitionState = SharedTransition.getState(this.transitionId);
514 if (!transitionState?.interactiveCancelled) {
515 this._transitioningDelegate = null;
516 // this.off('pan', this._interactiveDismissGesture);
517 if (this._modalAnimatedOptions) {
518 this._modalAnimatedOptions.pop();
519 }
520 }
521 whenClosedCallback();
522 });
523 }
524 [isEnabledProperty.getDefault]() {
525 const nativeView = this.nativeViewProtected;
526 return nativeView instanceof UIControl ? nativeView.enabled : true;
527 }
528 [isEnabledProperty.setNative](value) {
529 const nativeView = this.nativeViewProtected;
530 if (nativeView instanceof UIControl) {
531 nativeView.enabled = value;
532 }
533 }
534 [originXProperty.getDefault]() {
535 return this.nativeViewProtected.layer.anchorPoint.x;
536 }
537 [originXProperty.setNative](value) {
538 this.updateOriginPoint(value, this.originY);
539 }
540 [originYProperty.getDefault]() {
541 return this.nativeViewProtected.layer.anchorPoint.y;
542 }
543 [originYProperty.setNative](value) {
544 this.updateOriginPoint(this.originX, value);
545 }
546 [testIDProperty.setNative](value) {
547 this.setAccessibilityIdentifier(this.nativeViewProtected, value);
548 }
549 setAccessibilityIdentifier(view, value) {
550 view.accessibilityIdentifier = value;
551 if (this.testID && this.testID !== value)
552 this.testID = value;
553 if (this.accessibilityIdentifier !== value)
554 this.accessibilityIdentifier = value;
555 }
556 [accessibilityEnabledProperty.setNative](value) {
557 this.nativeViewProtected.isAccessibilityElement = !!value;
558 if (value) {
559 updateAccessibilityProperties(this);
560 }
561 }
562 [accessibilityIdentifierProperty.getDefault]() {
563 return this.nativeViewProtected.accessibilityIdentifier;
564 }
565 [accessibilityIdentifierProperty.setNative](value) {
566 this.setAccessibilityIdentifier(this.nativeViewProtected, value);
567 }
568 [accessibilityRoleProperty.setNative](value) {
569 this.accessibilityRole = value;
570 updateAccessibilityProperties(this);
571 }
572 [accessibilityValueProperty.setNative](value) {
573 value = value == null ? null : `${value}`;
574 this.nativeViewProtected.accessibilityValue = value;
575 }
576 [accessibilityLabelProperty.setNative](value) {
577 value = value == null ? null : `${value}`;
578 // not sure if needed for Label:
579 // if ((<any>this).nativeTextViewProtected) {
580 // (<any>this).nativeTextViewProtected.accessibilityLabel = value;
581 // } else {
582 this.nativeViewProtected.accessibilityLabel = value;
583 // }
584 }
585 [accessibilityHintProperty.setNative](value) {
586 value = value == null ? null : `${value}`;
587 this.nativeViewProtected.accessibilityHint = value;
588 }
589 [accessibilityIgnoresInvertColorsProperty.setNative](value) {
590 this.nativeViewProtected.accessibilityIgnoresInvertColors = !!value;
591 }
592 [accessibilityLanguageProperty.setNative](value) {
593 value = value == null ? null : `${value}`;
594 this.nativeViewProtected.accessibilityLanguage = value;
595 }
596 [accessibilityHiddenProperty.setNative](value) {
597 this.nativeViewProtected.accessibilityElementsHidden = !!value;
598 updateAccessibilityProperties(this);
599 }
600 [accessibilityLiveRegionProperty.setNative]() {
601 updateAccessibilityProperties(this);
602 }
603 [accessibilityStateProperty.setNative](value) {
604 this.accessibilityState = value;
605 updateAccessibilityProperties(this);
606 }
607 [accessibilityMediaSessionProperty.setNative]() {
608 updateAccessibilityProperties(this);
609 }
610 [isUserInteractionEnabledProperty.getDefault]() {
611 return this.nativeViewProtected.userInteractionEnabled;
612 }
613 [isUserInteractionEnabledProperty.setNative](value) {
614 this.nativeViewProtected.userInteractionEnabled = value;
615 }
616 [hiddenProperty.getDefault]() {
617 return this.nativeViewProtected.hidden;
618 }
619 [hiddenProperty.setNative](value) {
620 this.nativeViewProtected.hidden = value;
621 }
622 [visibilityProperty.getDefault]() {
623 return this.nativeViewProtected.hidden ? CoreTypes.Visibility.collapse : CoreTypes.Visibility.visible;
624 }
625 [visibilityProperty.setNative](value) {
626 const nativeView = this.nativeViewProtected;
627 switch (value) {
628 case CoreTypes.Visibility.visible:
629 nativeView.hidden = false;
630 break;
631 case CoreTypes.Visibility.hidden:
632 case CoreTypes.Visibility.collapse:
633 nativeView.hidden = true;
634 break;
635 default:
636 throw new Error(`Invalid visibility value: ${value}. Valid values are: "${CoreTypes.Visibility.visible}", "${CoreTypes.Visibility.hidden}", "${CoreTypes.Visibility.collapse}".`);
637 }
638 // Apply visibility value to shadows as well
639 if (nativeView.outerShadowContainerLayer) {
640 nativeView.outerShadowContainerLayer.hidden = nativeView.hidden;
641 }
642 }
643 [opacityProperty.getDefault]() {
644 return this.nativeViewProtected.alpha;
645 }
646 [opacityProperty.setNative](value) {
647 const nativeView = this.nativeViewProtected;
648 const updateSuspended = this._isPresentationLayerUpdateSuspended();
649 if (!updateSuspended) {
650 CATransaction.begin();
651 }
652 // Disable CALayer animatable property changes
653 CATransaction.setDisableActions(true);
654 nativeView.alpha = value;
655 // Apply opacity value to shadows as well
656 if (nativeView.outerShadowContainerLayer) {
657 nativeView.outerShadowContainerLayer.opacity = value;
658 }
659 CATransaction.setDisableActions(false);
660 if (!updateSuspended) {
661 CATransaction.commit();
662 }
663 }
664 [rotateProperty.getDefault]() {
665 return 0;
666 }
667 [rotateProperty.setNative](value) {
668 this.updateNativeTransform();
669 }
670 [rotateXProperty.getDefault]() {
671 return 0;
672 }
673 [rotateXProperty.setNative](value) {
674 this.updateNativeTransform();
675 }
676 [rotateYProperty.getDefault]() {
677 return 0;
678 }
679 [rotateYProperty.setNative](value) {
680 this.updateNativeTransform();
681 }
682 [perspectiveProperty.getDefault]() {
683 return 300;
684 }
685 [perspectiveProperty.setNative](value) {
686 this.updateNativeTransform();
687 }
688 [scaleXProperty.getDefault]() {
689 return 1;
690 }
691 [scaleXProperty.setNative](value) {
692 this.updateNativeTransform();
693 }
694 [scaleYProperty.getDefault]() {
695 return 1;
696 }
697 [scaleYProperty.setNative](value) {
698 this.updateNativeTransform();
699 }
700 [translateXProperty.getDefault]() {
701 return 0;
702 }
703 [translateXProperty.setNative](value) {
704 this.updateNativeTransform();
705 }
706 [translateYProperty.getDefault]() {
707 return 0;
708 }
709 [translateYProperty.setNative](value) {
710 this.updateNativeTransform();
711 }
712 [zIndexProperty.getDefault]() {
713 return 0;
714 }
715 [zIndexProperty.setNative](value) {
716 const nativeView = this.nativeViewProtected;
717 nativeView.layer.zPosition = value;
718 // Apply z-index to shadows as well
719 if (nativeView.outerShadowContainerLayer) {
720 nativeView.outerShadowContainerLayer.zPosition = value;
721 }
722 }
723 [backgroundInternalProperty.getDefault]() {
724 return this.nativeViewProtected.backgroundColor;
725 }
726 [backgroundInternalProperty.setNative](value) {
727 this._nativeBackgroundState = 'invalid';
728 if (this.isLayoutValid) {
729 this._redrawNativeBackground(value);
730 }
731 }
732 sendAccessibilityEvent(options) {
733 if (!isAccessibilityServiceEnabled()) {
734 return;
735 }
736 if (!options.iosNotificationType) {
737 return;
738 }
739 let notification;
740 let args = this.nativeViewProtected;
741 if (options?.message) {
742 args = options.message;
743 }
744 switch (options.iosNotificationType) {
745 case IOSPostAccessibilityNotificationType.Announcement: {
746 notification = UIAccessibilityAnnouncementNotification;
747 break;
748 }
749 case IOSPostAccessibilityNotificationType.Layout: {
750 notification = UIAccessibilityLayoutChangedNotification;
751 break;
752 }
753 case IOSPostAccessibilityNotificationType.Screen: {
754 notification = UIAccessibilityScreenChangedNotification;
755 break;
756 }
757 default: {
758 return;
759 }
760 }
761 UIAccessibilityPostNotification(notification, args ?? null);
762 }
763 accessibilityAnnouncement(msg = this.accessibilityLabel) {
764 this.sendAccessibilityEvent({
765 iosNotificationType: IOSPostAccessibilityNotificationType.Announcement,
766 message: msg,
767 });
768 }
769 accessibilityScreenChanged() {
770 this.sendAccessibilityEvent({
771 iosNotificationType: IOSPostAccessibilityNotificationType.Screen,
772 });
773 }
774 _getCurrentLayoutBounds() {
775 const nativeView = this.nativeViewProtected;
776 if (nativeView && !this.isCollapsed) {
777 const frame = nativeView.frame;
778 const origin = frame.origin;
779 const size = frame.size;
780 return {
781 left: Math.round(layout.toDevicePixels(origin.x)),
782 top: Math.round(layout.toDevicePixels(origin.y)),
783 right: Math.round(layout.toDevicePixels(origin.x + size.width)),
784 bottom: Math.round(layout.toDevicePixels(origin.y + size.height)),
785 };
786 }
787 else {
788 return { left: 0, top: 0, right: 0, bottom: 0 };
789 }
790 }
791 _redrawNativeBackground(value) {
792 const updateSuspended = this._isPresentationLayerUpdateSuspended();
793 if (!updateSuspended) {
794 CATransaction.begin();
795 }
796 // Disable CALayer animatable property changes
797 CATransaction.setDisableActions(true);
798 const nativeView = this.nativeViewProtected;
799 if (nativeView) {
800 if (value instanceof UIColor) {
801 nativeView.backgroundColor = value;
802 }
803 else {
804 iosBackground.createBackgroundUIColor(this, (color) => {
805 nativeView.backgroundColor = color;
806 });
807 this._setNativeClipToBounds();
808 }
809 }
810 CATransaction.setDisableActions(false);
811 if (!updateSuspended) {
812 CATransaction.commit();
813 }
814 this._nativeBackgroundState = 'drawn';
815 }
816 _setNativeClipToBounds() {
817 const view = this.nativeViewProtected;
818 if (view) {
819 const backgroundInternal = this.style.backgroundInternal;
820 view.clipsToBounds = view instanceof UIScrollView || backgroundInternal.hasBorderWidth() || backgroundInternal.hasBorderRadius();
821 }
822 }
823 _setupPopoverControllerDelegate(controller, parent) {
824 const popoverPresentationController = controller.popoverPresentationController;
825 this._popoverPresentationDelegate = IOSHelper.UIPopoverPresentationControllerDelegateImp.initWithOwnerAndCallback(new WeakRef(this), this._closeModalCallback);
826 popoverPresentationController.delegate = this._popoverPresentationDelegate;
827 let view;
828 do {
829 view = parent.nativeViewProtected;
830 parent = parent.parent;
831 } while (parent && !view);
832 // Note: sourceView and sourceRect are needed to specify the anchor location for the popover.
833 // Note: sourceView should be the button triggering the modal. If it the Page the popover might appear "behind" the page content
834 popoverPresentationController.sourceView = view;
835 popoverPresentationController.sourceRect = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);
836 }
837 _setupAdaptiveControllerDelegate(controller) {
838 this._adaptivePresentationDelegate = IOSHelper.UIAdaptivePresentationControllerDelegateImp.initWithOwnerAndCallback(new WeakRef(this), this._closeModalCallback);
839 if (controller?.presentationController) {
840 controller.presentationController.delegate = this._adaptivePresentationDelegate;
841 }
842 }
843}
844__decorate([
845 profile,
846 __metadata("design:type", Function),
847 __metadata("design:paramtypes", [Number, Number, Number, Number, Object]),
848 __metadata("design:returntype", void 0)
849], View.prototype, "layout", null);
850__decorate([
851 profile,
852 __metadata("design:type", Function),
853 __metadata("design:paramtypes", [Number, Number]),
854 __metadata("design:returntype", void 0)
855], View.prototype, "onMeasure", null);
856View.prototype._nativeBackgroundState = 'unset';
857var UIViewControllerTransitioningDelegateImpl = /** @class */ (function (_super) {
858 __extends(UIViewControllerTransitioningDelegateImpl, _super);
859 function UIViewControllerTransitioningDelegateImpl() {
860 return _super !== null && _super.apply(this, arguments) || this;
861 }
862 UIViewControllerTransitioningDelegateImpl.initWithOwner = function (owner) {
863 var delegate = UIViewControllerTransitioningDelegateImpl.new();
864 delegate.owner = owner;
865 return delegate;
866 };
867 UIViewControllerTransitioningDelegateImpl.prototype.animationControllerForDismissedController = function (dismissed) {
868 var _a;
869 var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
870 if (owner === null || owner === void 0 ? void 0 : owner.iosDismissedController) {
871 return owner.iosDismissedController(dismissed);
872 }
873 return null;
874 };
875 UIViewControllerTransitioningDelegateImpl.prototype.animationControllerForPresentedControllerPresentingControllerSourceController = function (presented, presenting, source) {
876 var _a;
877 var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
878 if (owner === null || owner === void 0 ? void 0 : owner.iosPresentedController) {
879 return owner.iosPresentedController(presented, presenting, source);
880 }
881 return null;
882 };
883 UIViewControllerTransitioningDelegateImpl.prototype.interactionControllerForDismissal = function (animator) {
884 var _a;
885 var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
886 if (owner === null || owner === void 0 ? void 0 : owner.iosInteractionDismiss) {
887 var transitionState = SharedTransition.getState(owner.id);
888 if (transitionState === null || transitionState === void 0 ? void 0 : transitionState.interactiveBegan) {
889 return owner.iosInteractionDismiss(animator);
890 }
891 }
892 return null;
893 };
894 UIViewControllerTransitioningDelegateImpl.prototype.interactionControllerForPresentation = function (animator) {
895 var _a;
896 var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
897 if (owner === null || owner === void 0 ? void 0 : owner.iosInteractionPresented) {
898 return owner.iosInteractionPresented(animator);
899 }
900 return null;
901 };
902 UIViewControllerTransitioningDelegateImpl.ObjCProtocols = [UIViewControllerTransitioningDelegate];
903 return UIViewControllerTransitioningDelegateImpl;
904}(NSObject));
905export class ContainerView extends View {
906 constructor() {
907 super();
908 this.iosOverflowSafeArea = true;
909 }
910}
911export class CustomLayoutView extends ContainerView {
912 createNativeView() {
913 const window = iosUtils.getWindow();
914 return UIView.alloc().initWithFrame(window ? window.screen.bounds : UIScreen.mainScreen.bounds);
915 }
916 get ios() {
917 return this.nativeViewProtected;
918 }
919 onMeasure(widthMeasureSpec, heightMeasureSpec) {
920 // Don't call super because it will set MeasureDimension. This method must be overridden and calculate its measuredDimensions.
921 }
922 _addViewToNativeVisualTree(child, atIndex) {
923 super._addViewToNativeVisualTree(child, atIndex);
924 const parentNativeView = this.nativeViewProtected;
925 const childNativeView = child.nativeViewProtected;
926 if (parentNativeView && childNativeView) {
927 if (typeof atIndex !== 'number' || atIndex >= parentNativeView.subviews.count) {
928 parentNativeView.addSubview(childNativeView);
929 }
930 else {
931 parentNativeView.insertSubviewAtIndex(childNativeView, atIndex);
932 }
933 // Add outer shadow layer manually as it belongs to parent layer tree (this is needed for reusable views)
934 if (childNativeView.outerShadowContainerLayer && !childNativeView.outerShadowContainerLayer.superlayer) {
935 parentNativeView.layer.insertSublayerBelow(childNativeView.outerShadowContainerLayer, childNativeView.layer);
936 }
937 return true;
938 }
939 return false;
940 }
941 _removeViewFromNativeVisualTree(child) {
942 super._removeViewFromNativeVisualTree(child);
943 if (child.nativeViewProtected) {
944 const nativeView = child.nativeViewProtected;
945 // Remove outer shadow layer manually as it belongs to parent layer tree
946 if (nativeView.outerShadowContainerLayer) {
947 nativeView.outerShadowContainerLayer.removeFromSuperlayer();
948 }
949 nativeView.removeFromSuperview();
950 }
951 }
952}
953//# sourceMappingURL=index.ios.js.map
\No newline at end of file