@nativescript/core
Version:
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
185 lines • 7.65 kB
JavaScript
import { SwitchBase, checkedProperty, offBackgroundColorProperty } from './switch-common';
import { colorProperty, backgroundColorProperty, backgroundInternalProperty } from '../styling/style-properties';
import { Color } from '../../color';
import { SDK_VERSION } from '../../utils/constants';
export * from './switch-common';
var SwitchChangeHandlerImpl = (function (_super) {
__extends(SwitchChangeHandlerImpl, _super);
function SwitchChangeHandlerImpl() {
return _super !== null && _super.apply(this, arguments) || this;
}
SwitchChangeHandlerImpl.initWithOwner = function (owner) {
var handler = SwitchChangeHandlerImpl.new();
handler._owner = owner;
return handler;
};
SwitchChangeHandlerImpl.prototype.valueChanged = function (sender) {
var _a;
var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.deref();
if (owner) {
checkedProperty.nativeValueChange(owner, sender.on);
}
};
SwitchChangeHandlerImpl.ObjCExposedMethods = {
valueChanged: { returns: interop.types.void, params: [UISwitch] },
};
return SwitchChangeHandlerImpl;
}(NSObject));
export class Switch extends SwitchBase {
constructor() {
super();
// Defer color updates while iOS 26+ "glass" toggle animation runs
this._toggleColorTimer = null;
}
createNativeView() {
return UISwitch.new();
}
initNativeView() {
super.initNativeView();
const nativeView = this.nativeViewProtected;
this._handler = SwitchChangeHandlerImpl.initWithOwner(new WeakRef(this));
nativeView.addTargetActionForControlEvents(this._handler, 'valueChanged', 4096 /* UIControlEvents.ValueChanged */);
}
disposeNativeView() {
this._handler = null;
if (this._toggleColorTimer) {
clearTimeout(this._toggleColorTimer);
this._toggleColorTimer = null;
}
super.disposeNativeView();
}
setNativeBackgroundColor(value) {
const native = this.nativeViewProtected;
if (value) {
const nativeValue = value instanceof Color ? value.ios : value;
// Keep the legacy behavior for on/off colors
native.onTintColor = nativeValue;
native.tintColor = nativeValue;
native.backgroundColor = nativeValue;
// Since iOS 16+ the control no longer clips its background by default.
// Ensure the track-shaped background doesn't bleed outside the control bounds.
if (SDK_VERSION >= 16) {
native.clipsToBounds = true;
native.layer.masksToBounds = true;
}
// Corner radius must be based on the final laid out size; use bounds first,
// then fall back to frame. If size isn't known yet, update on the next tick.
const height = native.bounds?.size?.height || native.frame?.size?.height || 0;
if (height > 0) {
native.layer.cornerRadius = height / 2;
}
else {
// Defer until after layout
setTimeout(() => {
const n = this.nativeViewProtected;
if (!n) {
return;
}
const h = n.bounds?.size?.height || n.frame?.size?.height || 0;
if (h > 0) {
n.layer.cornerRadius = h / 2;
}
}, 0);
}
}
else {
native.onTintColor = null;
native.tintColor = null;
native.backgroundColor = null;
native.layer.cornerRadius = 0;
if (SDK_VERSION >= 16) {
// Restore default clipping behavior
native.clipsToBounds = false;
native.layer.masksToBounds = false;
}
}
}
_onCheckedPropertyChanged(newValue) {
// only add :checked pseudo handling on supported iOS versions
// ios <13 works but causes glitchy animations when toggling
// so we decided to keep the old behavior on older versions.
if (SDK_VERSION >= 13) {
super._onCheckedPropertyChanged(newValue);
if (this.offBackgroundColor) {
const nextColor = !newValue ? this.offBackgroundColor : this.backgroundColor instanceof Color ? this.backgroundColor : new Color(this.backgroundColor);
// On iOS 26+, coordinate with the system's switch animation:
// delay applying track color until the toggle animation finishes to avoid a janky mid-animation recolor.
if (SDK_VERSION >= 26) {
if (this._toggleColorTimer) {
clearTimeout(this._toggleColorTimer);
}
this._toggleColorTimer = setTimeout(() => {
const ANIMATION_DELAY_MS = 0.26; // approx. system toggle duration
UIView.animateWithDurationAnimations(ANIMATION_DELAY_MS, () => {
this._toggleColorTimer = null;
this.setNativeBackgroundColor(nextColor);
});
}, 0);
}
else {
this.setNativeBackgroundColor(nextColor);
}
}
}
}
// @ts-ignore
get ios() {
return this.nativeViewProtected;
}
[checkedProperty.getDefault]() {
return false;
}
[checkedProperty.setNative](value) {
this.nativeViewProtected.on = value;
}
[colorProperty.getDefault]() {
return this.nativeViewProtected.thumbTintColor;
}
[colorProperty.setNative](value) {
const color = value instanceof Color ? value.ios : value;
this.nativeViewProtected.thumbTintColor = color;
if (color && this.nativeViewProtected.subviews.count > 0) {
const alpha = new interop.Reference(1.0);
const res = color.getRedGreenBlueAlpha(null, null, null, alpha);
this.nativeViewProtected.subviews[0].alpha = (res && alpha.value) ?? 1;
}
}
[backgroundColorProperty.getDefault]() {
return this.nativeViewProtected.onTintColor;
}
[backgroundColorProperty.setNative](value) {
if (SDK_VERSION >= 13) {
if (!this.offBackgroundColor || this.checked) {
this.setNativeBackgroundColor(value);
}
}
else {
// old behavior on unsupported iOS versions
this.nativeViewProtected.onTintColor = value instanceof Color ? value.ios : value;
}
}
[backgroundInternalProperty.getDefault]() {
return null;
}
[backgroundInternalProperty.setNative](value) {
//
}
[offBackgroundColorProperty.getDefault]() {
return this.nativeViewProtected.backgroundColor;
}
[offBackgroundColorProperty.setNative](value) {
if (SDK_VERSION >= 13) {
if (!this.checked) {
this.setNativeBackgroundColor(value);
}
}
else {
// old behavior on unsupported iOS versions...
const nativeValue = value instanceof Color ? value.ios : value;
this.nativeViewProtected.tintColor = nativeValue;
this.nativeViewProtected.backgroundColor = nativeValue;
this.nativeViewProtected.layer.cornerRadius = this.nativeViewProtected.frame.size.height / 2;
}
}
}
//# sourceMappingURL=index.ios.js.map