mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(ios): iosGlassEffect property
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
<Button text="datepicker" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="datepicker" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="dialogs" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="dialogs" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="forms" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="forms" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
|
<Button text="glass-effects" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="image-async" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="image-async" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="image-handling" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="image-handling" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="labels" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="labels" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
|
|||||||
16
apps/toolbox/src/pages/glass-effects.ts
Normal file
16
apps/toolbox/src/pages/glass-effects.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Observable, EventData, Page, CoreTypes, GlassEffectConfig } from '@nativescript/core';
|
||||||
|
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
export function navigatingTo(args: EventData) {
|
||||||
|
page = <Page>args.object;
|
||||||
|
page.bindingContext = new GlassEffectModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GlassEffectModel extends Observable {
|
||||||
|
iosGlassEffectInteractive: GlassEffectConfig = {
|
||||||
|
interactive: true,
|
||||||
|
tint: '#faabab',
|
||||||
|
variant: 'clear',
|
||||||
|
};
|
||||||
|
}
|
||||||
27
apps/toolbox/src/pages/glass-effects.xml
Normal file
27
apps/toolbox/src/pages/glass-effects.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||||
|
<Page.actionBar>
|
||||||
|
<ActionBar title="Glass Effects" class="action-bar">
|
||||||
|
</ActionBar>
|
||||||
|
</Page.actionBar>
|
||||||
|
|
||||||
|
<GridLayout>
|
||||||
|
|
||||||
|
<Image src="https://cdn.wallpapersafari.com/89/64/c6MnRY.jpg" stretch="aspectFill" iosOverflowSafeArea="true" />
|
||||||
|
|
||||||
|
<GridLayout rows="*,auto,auto,auto,*">
|
||||||
|
|
||||||
|
<GridLayout row="1" width="300" height="150" iosGlassEffect="regular" horizontalAlignment="center" verticalAlignment="middle">
|
||||||
|
<Label class="text-center c-white" fontWeight="bold" fontSize="18" text="Glass Effects Regular" />
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout row="2" width="300" height="150" iosGlassEffect="clear" horizontalAlignment="center" verticalAlignment="middle" class="m-t-10">
|
||||||
|
<Label class="text-center c-white" fontWeight="bold" fontSize="18" text="Glass Effects Clear" />
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout row="3" width="300" height="150" iosGlassEffect="{{iosGlassEffectInteractive}}" horizontalAlignment="center" verticalAlignment="middle" class="m-t-10">
|
||||||
|
<Label class="text-center c-white" fontWeight="bold" fontSize="18" text="Glass Effects Interactive" />
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
</GridLayout>
|
||||||
|
</Page>
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
import { Point, Position, View as ViewDefinition } from '.';
|
import { Point, Position, View as ViewDefinition } from '.';
|
||||||
|
|
||||||
// Requires
|
// Requires
|
||||||
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty } from './view-common';
|
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty, iosGlassEffectProperty, GlassEffectType, GlassEffectVariant } from './view-common';
|
||||||
import { ShowModalOptions, hiddenProperty } from '../view-base';
|
import { ShowModalOptions, hiddenProperty } from '../view-base';
|
||||||
import { Trace } from '../../../trace';
|
import { Trace } from '../../../trace';
|
||||||
import { layout, ios as iosUtils, SDK_VERSION } from '../../../utils';
|
import { layout, ios as iosUtils } from '../../../utils';
|
||||||
|
import { SDK_VERSION, supportsGlass } from '../../../utils/constants';
|
||||||
import { IOSHelper } from './view-helper';
|
import { IOSHelper } from './view-helper';
|
||||||
import { ios as iosBackground, Background } from '../../styling/background';
|
import { ios as iosBackground, Background } from '../../styling/background';
|
||||||
import { perspectiveProperty, visibilityProperty, opacityProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty } from '../../styling/style-properties';
|
import { perspectiveProperty, visibilityProperty, opacityProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty } from '../../styling/style-properties';
|
||||||
@@ -16,6 +17,7 @@ import { CoreTypes } from '../../../core-types';
|
|||||||
import type { ModalTransition } from '../../transition/modal-transition';
|
import type { ModalTransition } from '../../transition/modal-transition';
|
||||||
import { SharedTransition } from '../../transition/shared-transition';
|
import { SharedTransition } from '../../transition/shared-transition';
|
||||||
import { NativeScriptUIView } from '../../utils';
|
import { NativeScriptUIView } from '../../utils';
|
||||||
|
import { Color } from '../../../color';
|
||||||
|
|
||||||
export * from './view-common';
|
export * from './view-common';
|
||||||
// helpers (these are okay re-exported here)
|
// helpers (these are okay re-exported here)
|
||||||
@@ -53,6 +55,12 @@ export class View extends ViewCommon implements ViewDefinition {
|
|||||||
*/
|
*/
|
||||||
_nativeBackgroundState: 'unset' | 'invalid' | 'drawn';
|
_nativeBackgroundState: 'unset' | 'invalid' | 'drawn';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Glass effect configuration
|
||||||
|
*/
|
||||||
|
private _glassEffectView: UIVisualEffectView;
|
||||||
|
private _glassEffectMeasure: NodeJS.Timeout;
|
||||||
|
|
||||||
get isLayoutRequired(): boolean {
|
get isLayoutRequired(): boolean {
|
||||||
return (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
|
return (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
|
||||||
}
|
}
|
||||||
@@ -889,6 +897,60 @@ export class View extends ViewCommon implements ViewDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[iosGlassEffectProperty.setNative](value: GlassEffectType) {
|
||||||
|
if (!this.nativeViewProtected || !supportsGlass()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._glassEffectView) {
|
||||||
|
this._glassEffectView.removeFromSuperview();
|
||||||
|
this._glassEffectView = null;
|
||||||
|
}
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let effect: UIGlassEffect;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
effect = UIGlassEffect.effectWithStyle(this.toUIGlassStyle(value));
|
||||||
|
} else {
|
||||||
|
if (value.variant === 'identity') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
effect = UIGlassEffect.effectWithStyle(this.toUIGlassStyle(value.variant));
|
||||||
|
if (value.interactive) {
|
||||||
|
effect.interactive = true;
|
||||||
|
}
|
||||||
|
if (value.tint) {
|
||||||
|
effect.tintColor = typeof value.tint === 'string' ? new Color(value.tint).ios : value.tint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._glassEffectView = UIVisualEffectView.alloc().initWithEffect(effect);
|
||||||
|
// let touches pass to content
|
||||||
|
this._glassEffectView.userInteractionEnabled = false;
|
||||||
|
this._glassEffectView.clipsToBounds = true;
|
||||||
|
// size & autoresize
|
||||||
|
if (this._glassEffectMeasure) {
|
||||||
|
clearTimeout(this._glassEffectMeasure);
|
||||||
|
}
|
||||||
|
this._glassEffectMeasure = setTimeout(() => {
|
||||||
|
const size = this.nativeViewProtected.bounds.size;
|
||||||
|
this._glassEffectView.frame = CGRectMake(0, 0, size.width, size.height);
|
||||||
|
this._glassEffectView.autoresizingMask = 2;
|
||||||
|
this.nativeViewProtected.insertSubviewAtIndex(this._glassEffectView, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public toUIGlassStyle(value?: GlassEffectVariant) {
|
||||||
|
if (supportsGlass()) {
|
||||||
|
switch (value) {
|
||||||
|
case 'regular':
|
||||||
|
return UIGlassEffectStyle?.Regular ?? 0;
|
||||||
|
case 'clear':
|
||||||
|
return UIGlassEffectStyle?.Clear ?? 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
public sendAccessibilityEvent(options: Partial<AccessibilityEventOptions>): void {
|
public sendAccessibilityEvent(options: Partial<AccessibilityEventOptions>): void {
|
||||||
if (!isAccessibilityServiceEnabled()) {
|
if (!isAccessibilityServiceEnabled()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1293,6 +1293,7 @@ export const isUserInteractionEnabledProperty = new Property<ViewCommon, boolean
|
|||||||
});
|
});
|
||||||
isUserInteractionEnabledProperty.register(ViewCommon);
|
isUserInteractionEnabledProperty.register(ViewCommon);
|
||||||
|
|
||||||
|
// Apple only
|
||||||
export const iosOverflowSafeAreaProperty = new Property<ViewCommon, boolean>({
|
export const iosOverflowSafeAreaProperty = new Property<ViewCommon, boolean>({
|
||||||
name: 'iosOverflowSafeArea',
|
name: 'iosOverflowSafeArea',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
@@ -1313,6 +1314,17 @@ export const iosIgnoreSafeAreaProperty = new InheritedProperty({
|
|||||||
});
|
});
|
||||||
iosIgnoreSafeAreaProperty.register(ViewCommon);
|
iosIgnoreSafeAreaProperty.register(ViewCommon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Glass effects
|
||||||
|
*/
|
||||||
|
export type GlassEffectVariant = 'regular' | 'clear' | 'identity';
|
||||||
|
export type GlassEffectConfig = { variant?: GlassEffectVariant; interactive?: boolean; tint: string | Color };
|
||||||
|
export type GlassEffectType = GlassEffectVariant | GlassEffectConfig;
|
||||||
|
export const iosGlassEffectProperty = new Property<ViewCommon, GlassEffectType>({
|
||||||
|
name: 'iosGlassEffect',
|
||||||
|
});
|
||||||
|
iosGlassEffectProperty.register(ViewCommon);
|
||||||
|
|
||||||
export const visionHoverStyleProperty = new Property<ViewCommon, string | VisionHoverOptions>({
|
export const visionHoverStyleProperty = new Property<ViewCommon, string | VisionHoverOptions>({
|
||||||
name: 'visionHoverStyle',
|
name: 'visionHoverStyle',
|
||||||
valueChanged(view, oldValue, newValue) {
|
valueChanged(view, oldValue, newValue) {
|
||||||
@@ -1329,6 +1341,7 @@ const visionIgnoreHoverStyleProperty = new Property<ViewCommon, boolean>({
|
|||||||
valueConverter: booleanConverter,
|
valueConverter: booleanConverter,
|
||||||
});
|
});
|
||||||
visionIgnoreHoverStyleProperty.register(ViewCommon);
|
visionIgnoreHoverStyleProperty.register(ViewCommon);
|
||||||
|
// Apple only end
|
||||||
|
|
||||||
const touchAnimationProperty = new Property<ViewCommon, boolean | TouchAnimationOptions>({
|
const touchAnimationProperty = new Property<ViewCommon, boolean | TouchAnimationOptions>({
|
||||||
name: 'touchAnimation',
|
name: 'touchAnimation',
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export { ControlStateChangeListener } from './core/control-state-change';
|
|||||||
export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, querySelectorAll } from './core/view-base';
|
export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, querySelectorAll } from './core/view-base';
|
||||||
export type { ShowModalOptions } from './core/view-base';
|
export type { ShowModalOptions } from './core/view-base';
|
||||||
export { View, CSSType, ContainerView, ViewHelper, AndroidHelper, IOSHelper, isUserInteractionEnabledProperty, PseudoClassHandler, CustomLayoutView } from './core/view';
|
export { View, CSSType, ContainerView, ViewHelper, AndroidHelper, IOSHelper, isUserInteractionEnabledProperty, PseudoClassHandler, CustomLayoutView } from './core/view';
|
||||||
export type { Template, KeyedTemplate, ShownModallyData, AddArrayFromBuilder, AddChildFromBuilder, Size } from './core/view';
|
export type { Template, KeyedTemplate, ShownModallyData, AddArrayFromBuilder, AddChildFromBuilder, Size, GlassEffectConfig, GlassEffectType, GlassEffectVariant } from './core/view';
|
||||||
export { Property, CoercibleProperty, InheritedProperty, CssProperty, InheritedCssProperty, ShorthandProperty, CssAnimationProperty, unsetValue, makeParser, makeValidator } from './core/properties';
|
export { Property, CoercibleProperty, InheritedProperty, CssProperty, InheritedCssProperty, ShorthandProperty, CssAnimationProperty, unsetValue, makeParser, makeValidator } from './core/properties';
|
||||||
export { addWeakEventListener, removeWeakEventListener } from './core/weak-event-listener';
|
export { addWeakEventListener, removeWeakEventListener } from './core/weak-event-listener';
|
||||||
export { DatePicker } from './date-picker';
|
export { DatePicker } from './date-picker';
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
export const SDK_VERSION = android.os.Build.VERSION.SDK_INT;
|
export const SDK_VERSION = android.os.Build.VERSION.SDK_INT;
|
||||||
|
export function supportsGlass(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
1
packages/core/utils/constants.d.ts
vendored
1
packages/core/utils/constants.d.ts
vendored
@@ -1 +1,2 @@
|
|||||||
export const SDK_VERSION: number;
|
export const SDK_VERSION: number;
|
||||||
|
export function supportsGlass(): boolean;
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
export const SDK_VERSION = parseFloat(UIDevice.currentDevice.systemVersion);
|
export const SDK_VERSION = parseFloat(UIDevice.currentDevice.systemVersion);
|
||||||
|
export function supportsGlass(): boolean {
|
||||||
|
return __APPLE__ && SDK_VERSION >= 26;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user