Skip to content

Commit 987749c

Browse files
Merge pull request #5 from TheOriginalJosh/ios-shadow
Adding wrapping StackLayout to container.
2 parents 9337744 + ffa5a9d commit 987749c

File tree

2 files changed

+91
-70
lines changed

2 files changed

+91
-70
lines changed

app/home/home.component.ios.html

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,10 @@
44

55
<GridLayout rows="*, auto" columns="*" class="page">
66
<StackLayout row="0" col="0">
7-
<StackLayout [shadow]="elevation">
8-
<Label class="h3 m-15 p-10 ex1" [text]="'shadow=\''+elevation+'\''"></Label>
9-
</StackLayout>
10-
<StackLayout shadow [elevation]="elevation">
11-
<Label class="h3 m-15 p-10 ex2" [text]="'shadow elevation=\''+elevation+'\''"></Label>
12-
</StackLayout>
13-
<StackLayout shadow [elevation]="elevation" [shadowOffset]="4">
14-
<Label class="h3 m-15 p-10 ex3" [text]="'shadow [elevation]=\''+elevation+'\' shadowOffset=\'4\''"></Label>
15-
</StackLayout>
16-
<StackLayout shadow [elevation]="elevation">
17-
<Label class="h1 m-15 p-15 ex4" text=""></Label>
18-
</StackLayout>
7+
<Label [shadow]="elevation" class="h3 m-15 p-10 ex1" [text]="'shadow=\''+elevation+'\''"></Label>
8+
<Label shadow [elevation]="elevation" class="h3 m-15 p-10 ex2" [text]="'shadow elevation=\''+elevation+'\''"></Label>
9+
<Label shadow [elevation]="elevation" [shadowOffset]="4" class="h3 m-15 p-10 ex3" [text]="'shadow [elevation]=\''+elevation+'\' shadowOffset=\'4\''"></Label>
10+
<Label shadow [elevation]="elevation" class="h1 m-15 p-15 ex4" text=""></Label>
1911
</StackLayout>
2012
<ListPicker row="1" col="0" [items]="stdElevations" selectedIndex="2" (selectedIndexChange)="setElevation($event)" class="p-15"></ListPicker>
21-
</GridLayout>
13+
</GridLayout>

lib/src/nativescript-ngx-shadow/ng-shadow.directive.ts

Lines changed: 86 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@ import {
55
Input,
66
OnChanges,
77
OnInit,
8-
SimpleChanges
9-
} from "@angular/core";
10-
import { isAndroid, isIOS } from "tns-core-modules/platform";
11-
12-
import { AndroidData } from "./common/android-data.model";
13-
import { IOSData } from "./common/ios-data.model";
14-
import { Shadow } from "./common/shadow";
15-
import { Shape, ShapeEnum } from "./common/shape.enum";
16-
8+
SimpleChanges,
9+
Renderer2,
10+
AfterViewInit
11+
} from '@angular/core';
12+
import { isAndroid, isIOS } from 'tns-core-modules/platform';
13+
14+
import { AndroidData } from './common/android-data.model';
15+
import { IOSData } from './common/ios-data.model';
16+
import { Shadow } from './common/shadow';
17+
import { Shape, ShapeEnum } from './common/shape.enum';
18+
import { View } from 'tns-core-modules/ui/page/page';
19+
import { StackLayout } from 'tns-core-modules/ui/layouts/stack-layout';
1720
declare const android: any;
1821

19-
@Directive({ selector: "[shadow]" })
20-
export class NativeShadowDirective implements OnInit, OnChanges {
22+
@Directive({ selector: '[shadow]' })
23+
export class NativeShadowDirective implements OnInit, OnChanges, AfterViewInit {
2124
@Input() shadow: string | AndroidData | IOSData;
2225
@Input() elevation?: number | string;
2326
@Input() pressedElevation?: number | string;
@@ -37,9 +40,10 @@ export class NativeShadowDirective implements OnInit, OnChanges {
3740
private initialized = false;
3841
private originalNSFn: any;
3942
private previousNSFn: any;
43+
private iosShadowRapper: View;
4044

41-
constructor(private el: ElementRef) {
42-
if(isAndroid) {
45+
constructor(private el: ElementRef, private render: Renderer2) {
46+
if (isAndroid) {
4347
this.originalNSFn = this.el.nativeElement._redrawNativeBackground; //always store the original method
4448
}
4549
}
@@ -62,7 +66,7 @@ export class NativeShadowDirective implements OnInit, OnChanges {
6266
this.initialized = true;
6367
}
6468

65-
@HostListener("loaded")
69+
@HostListener('loaded')
6670
onLoaded() {
6771
this.loaded = true;
6872
// Weirdly ngOnInit isn't called on iOS on demo app
@@ -82,38 +86,57 @@ export class NativeShadowDirective implements OnInit, OnChanges {
8286
}
8387
}
8488

85-
@HostListener("unloaded")
89+
private addIosWrapper() {
90+
if (isIOS) {
91+
const originalElement = this.el.nativeElement as View;
92+
93+
this.iosShadowRapper = this.render.createElement(
94+
'StackLayout'
95+
) as StackLayout;
96+
97+
// wrappingElement.cssClasses = mainElement.cssClasses;
98+
const parent = originalElement.parentNode;
99+
this.render.insertBefore(parent, this.iosShadowRapper, originalElement);
100+
this.render.removeChild(parent, originalElement);
101+
this.render.appendChild(this.iosShadowRapper, originalElement);
102+
}
103+
}
104+
105+
@HostListener('unloaded')
86106
onUnloaded() {
87107
this.loaded = false;
88108

89109
if (isAndroid) {
90110
this.el.nativeElement._redrawNativeBackground = this.originalNSFn; // always revert to the original method
91111
}
92112
}
113+
ngAfterViewInit() {
114+
this.addIosWrapper();
115+
}
93116

94117
ngOnChanges(changes: SimpleChanges) {
95118
if (
96119
this.loaded &&
97120
!!changes &&
98-
(changes.hasOwnProperty("shadow") ||
99-
changes.hasOwnProperty("elevation") ||
100-
changes.hasOwnProperty("pressedElevation") ||
101-
changes.hasOwnProperty("shape") ||
102-
changes.hasOwnProperty("bgcolor") ||
103-
changes.hasOwnProperty("cornerRadius") ||
104-
changes.hasOwnProperty("pressedTranslationZ") ||
105-
changes.hasOwnProperty("forcePressAnimation") ||
106-
changes.hasOwnProperty("translationZ") ||
107-
changes.hasOwnProperty("maskToBounds") ||
108-
changes.hasOwnProperty("shadowColor") ||
109-
changes.hasOwnProperty("shadowOffset") ||
110-
changes.hasOwnProperty("shadowOpacity") ||
111-
changes.hasOwnProperty("shadowRadius"))
121+
(changes.hasOwnProperty('shadow') ||
122+
changes.hasOwnProperty('elevation') ||
123+
changes.hasOwnProperty('pressedElevation') ||
124+
changes.hasOwnProperty('shape') ||
125+
changes.hasOwnProperty('bgcolor') ||
126+
changes.hasOwnProperty('cornerRadius') ||
127+
changes.hasOwnProperty('pressedTranslationZ') ||
128+
changes.hasOwnProperty('forcePressAnimation') ||
129+
changes.hasOwnProperty('translationZ') ||
130+
changes.hasOwnProperty('maskToBounds') ||
131+
changes.hasOwnProperty('shadowColor') ||
132+
changes.hasOwnProperty('shadowOffset') ||
133+
changes.hasOwnProperty('shadowOpacity') ||
134+
changes.hasOwnProperty('shadowRadius'))
112135
) {
113136
if (
114-
changes.hasOwnProperty("shadow") &&
115-
!changes.hasOwnProperty("elevation") &&
116-
typeof changes.shadow.currentValue === "number"
137+
changes.hasOwnProperty('shadow') &&
138+
!changes.hasOwnProperty('elevation') &&
139+
typeof changes.shadow.currentValue === 'number'
117140
) {
118141
this.elevation = changes.shadow.currentValue;
119142
}
@@ -128,16 +151,16 @@ export class NativeShadowDirective implements OnInit, OnChanges {
128151
}
129152
}
130153

131-
private monkeyPatch = (val) => {
154+
private monkeyPatch = val => {
132155
this.previousNSFn.call(this.el.nativeElement, val);
133156
this.applyShadow();
134-
}
157+
};
135158

136159
private applyShadow() {
137160
if (
138161
this.shadow === null ||
139162
this.shadow === undefined ||
140-
(this.shadow === "" && !this.elevation)
163+
(this.shadow === '' && !this.elevation)
141164
) {
142165
return;
143166
}
@@ -150,53 +173,59 @@ export class NativeShadowDirective implements OnInit, OnChanges {
150173
}
151174
}
152175

153-
Shadow.apply(this.el.nativeElement, {
154-
elevation: this.elevation as number,
155-
pressedElevation: this.pressedElevation as number,
156-
shape: this.shape,
157-
bgcolor: this.bgcolor,
158-
cornerRadius: this.cornerRadius,
159-
translationZ: this.translationZ,
160-
pressedTranslationZ: this.pressedTranslationZ,
161-
forcePressAnimation: this.forcePressAnimation,
162-
maskToBounds: this.maskToBounds,
163-
shadowColor: this.shadowColor,
164-
shadowOffset: this.shadowOffset as number,
165-
shadowOpacity: this.shadowOpacity as number,
166-
shadowRadius: this.shadowRadius as number
167-
});
176+
const viewToApplyShadowTo = isIOS
177+
? this.iosShadowRapper
178+
: this.el.nativeElement;
179+
180+
if (viewToApplyShadowTo) {
181+
Shadow.apply(viewToApplyShadowTo, {
182+
elevation: this.elevation as number,
183+
pressedElevation: this.pressedElevation as number,
184+
shape: this.shape,
185+
bgcolor: this.bgcolor,
186+
cornerRadius: this.cornerRadius,
187+
translationZ: this.translationZ,
188+
pressedTranslationZ: this.pressedTranslationZ,
189+
forcePressAnimation: this.forcePressAnimation,
190+
maskToBounds: this.maskToBounds,
191+
shadowColor: this.shadowColor,
192+
shadowOffset: this.shadowOffset as number,
193+
shadowOpacity: this.shadowOpacity as number,
194+
shadowRadius: this.shadowRadius as number
195+
});
196+
}
168197
}
169198

170199
private initializeCommonData() {
171200
const tShadow = typeof this.shadow;
172-
if ((tShadow === "string" || tShadow === "number") && !this.elevation) {
201+
if ((tShadow === 'string' || tShadow === 'number') && !this.elevation) {
173202
this.elevation = this.shadow ? parseInt(this.shadow as string, 10) : 2;
174203
}
175204
const tElevation = typeof this.elevation;
176-
if (tElevation === "string" || tElevation === "number") {
205+
if (tElevation === 'string' || tElevation === 'number') {
177206
this.elevation = this.elevation
178207
? parseInt(this.elevation as string, 10)
179208
: 2;
180209
}
181210
}
182211

183212
private initializeAndroidData() {
184-
if (typeof this.cornerRadius === "string") {
213+
if (typeof this.cornerRadius === 'string') {
185214
this.cornerRadius = parseInt(this.cornerRadius, 10);
186215
}
187-
if (typeof this.translationZ === "string") {
216+
if (typeof this.translationZ === 'string') {
188217
this.translationZ = parseInt(this.translationZ, 10);
189218
}
190219
}
191220

192221
private initializeIOSData() {
193-
if (typeof this.shadowOffset === "string") {
222+
if (typeof this.shadowOffset === 'string') {
194223
this.shadowOffset = parseFloat(this.shadowOffset);
195224
}
196-
if (typeof this.shadowOpacity === "string") {
225+
if (typeof this.shadowOpacity === 'string') {
197226
this.shadowOpacity = parseFloat(this.shadowOpacity);
198227
}
199-
if (typeof this.shadowRadius === "string") {
228+
if (typeof this.shadowRadius === 'string') {
200229
this.shadowRadius = parseFloat(this.shadowRadius);
201230
}
202231
}

0 commit comments

Comments
 (0)