mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
feat(core): box shadow demo (#9182)
This commit is contained in:

committed by
Nathan Walker

parent
b745e0c5d4
commit
ad92ba567f
@ -5,17 +5,79 @@
|
||||
The following CSS rule changes the font size of all UI
|
||||
components that have the btn class name.
|
||||
*/
|
||||
.btn {
|
||||
.btn-view-demo {
|
||||
font-size: 18;
|
||||
/* box-shadow: -5 -5 10 10 navy; */
|
||||
box-shadow: -5 -5 rgba(0,0,0,0.5);
|
||||
background-color: #add8e6;
|
||||
color: navy;
|
||||
/* TODO: adding border radius breaks shadow */
|
||||
/* border-radius: 10; */
|
||||
background-color: #65ADF1;
|
||||
border-radius: 5;
|
||||
font-size: 17;
|
||||
padding: 15;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bold{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.controls Label {
|
||||
font-size: 20;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-top: 10;
|
||||
}
|
||||
|
||||
.controls Button {
|
||||
padding: 10 15;
|
||||
margin: 5;
|
||||
font-size: 17;
|
||||
font-weight: bold;
|
||||
color: #65ADF1;
|
||||
border-radius: 5;
|
||||
border-width: 1;
|
||||
border-color: #65ADF1;
|
||||
}
|
||||
|
||||
.box-shadow-demo .demo-component {
|
||||
font-size: 20;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
border-color: #555;
|
||||
margin: 10;
|
||||
padding: 20 25;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.box-shadow-demo .box-shadow-prop-controls {
|
||||
padding: 10;
|
||||
color: #333;
|
||||
font-size: 17;
|
||||
}
|
||||
|
||||
.box-shadow-demo .box-shadow-prop-controls TextField{
|
||||
margin-left: 10;
|
||||
padding: 5;
|
||||
border-bottom-width: 1;
|
||||
border-color: #65ADF1;
|
||||
}
|
||||
|
||||
.box-shadow-demo .controls .description {
|
||||
font-size: 15;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
margin-bottom: 10;
|
||||
}
|
||||
|
||||
.box-shadow-demo .controls Button[selectedAttr=true] {
|
||||
background-color: #65ADF1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.box-shadow-prop-controls .btn-apply {
|
||||
background-color: #65ADF1;
|
||||
color: #fff;
|
||||
padding: 10 15;
|
||||
border-radius: 4;
|
||||
margin-left: 10;
|
||||
font-size: 17;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
177
apps/toolbox/src/box-shadow.ts
Normal file
177
apps/toolbox/src/box-shadow.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import { Observable } from '@nativescript/core';
|
||||
import { EventData, Page } from '@nativescript/core';
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
const page = <Page>args.object;
|
||||
page.bindingContext = new BoxShadowModel();
|
||||
}
|
||||
|
||||
export class BoxShadowModel extends Observable {
|
||||
private _selectedComponentType: string;
|
||||
private _selectedBackgroundType: string;
|
||||
private _selectedBorderType: string;
|
||||
private _selectedAnimation: string;
|
||||
private _boxShadow: string;
|
||||
|
||||
background: string;
|
||||
borderWidth: number;
|
||||
borderRadius: number;
|
||||
appliedBoxShadow: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
get selectedComponentType(): string {
|
||||
return this._selectedComponentType;
|
||||
}
|
||||
|
||||
set selectedComponentType(value: string) {
|
||||
if (this._selectedComponentType !== value) {
|
||||
this._selectedComponentType = value;
|
||||
this.notifyPropertyChange('selectedComponentType', value);
|
||||
}
|
||||
}
|
||||
|
||||
get selectedBackgroundType(): string {
|
||||
return this._selectedBackgroundType;
|
||||
}
|
||||
|
||||
set selectedBackgroundType(value: string) {
|
||||
if (this._selectedBackgroundType !== value) {
|
||||
this._selectedBackgroundType = value;
|
||||
this.notifyPropertyChange('selectedBackgroundType', value);
|
||||
switch (value) {
|
||||
case 'solid':
|
||||
this.background = '#65ADF1';
|
||||
break;
|
||||
case 'gradient':
|
||||
this.background = 'linear-gradient(to top, #65ADF1, white)';
|
||||
break;
|
||||
case 'transparent':
|
||||
this.background = 'transparent';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.notifyPropertyChange('background', this.background);
|
||||
}
|
||||
}
|
||||
|
||||
get selectedBorderType(): string {
|
||||
return this._selectedBorderType;
|
||||
}
|
||||
|
||||
set selectedBorderType(value: string) {
|
||||
this._selectedBorderType = value;
|
||||
this.notifyPropertyChange('selectedBorderType', value);
|
||||
switch (value) {
|
||||
case 'solid':
|
||||
this.borderWidth = this.borderWidth ? 0 : 2;
|
||||
break;
|
||||
case 'rounded':
|
||||
this.borderRadius = this.borderRadius ? 0 : 10;
|
||||
break;
|
||||
case 'none':
|
||||
this.borderRadius = 0;
|
||||
this.borderWidth = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.notifyPropertyChange('borderRadius', this.borderRadius);
|
||||
this.notifyPropertyChange('borderWidth', this.borderWidth);
|
||||
}
|
||||
|
||||
selectComponentType(args): void {
|
||||
this.selectedComponentType = args.object.componentType;
|
||||
}
|
||||
|
||||
selectBackgroundType(args): void {
|
||||
this.selectedBackgroundType = args.object.backgroundType;
|
||||
}
|
||||
|
||||
selectBorderType(args): void {
|
||||
this.selectedBorderType = args.object.borderType;
|
||||
}
|
||||
|
||||
selectAnimationType(args): void {
|
||||
this._selectedAnimation = args.object.animationType;
|
||||
}
|
||||
|
||||
applyBoxShadow(): void {
|
||||
if (!this._boxShadow) {
|
||||
this._boxShadow = '';
|
||||
}
|
||||
this.appliedBoxShadow = this._boxShadow;
|
||||
this.notifyPropertyChange('appliedBoxShadow', this.appliedBoxShadow);
|
||||
|
||||
// TODO: this is a workaround to apply shadow immediately,
|
||||
// since the box-shadow logic is currently inside background.ts
|
||||
this.notifyPropertyChange('background', '');
|
||||
this.notifyPropertyChange('background', this.background);
|
||||
}
|
||||
|
||||
textChange(args): void {
|
||||
this._boxShadow = args.object.text;
|
||||
}
|
||||
|
||||
toggleAnimation(args) {
|
||||
const view = args.object;
|
||||
const animationDuration = 500;
|
||||
if (this._selectedAnimation === 'width') {
|
||||
const originalWidth = args.object.getActualSize().width;
|
||||
view
|
||||
.animate({
|
||||
width: originalWidth / 2,
|
||||
duration: animationDuration,
|
||||
})
|
||||
.then(() =>
|
||||
view.animate({
|
||||
width: originalWidth,
|
||||
duration: animationDuration,
|
||||
})
|
||||
)
|
||||
.catch((err) => {
|
||||
console.error('animation error', err);
|
||||
});
|
||||
} else if (this._selectedAnimation === 'height') {
|
||||
const originalHeight = args.object.getActualSize().height;
|
||||
view
|
||||
.animate({
|
||||
height: originalHeight / 2,
|
||||
duration: animationDuration,
|
||||
})
|
||||
.then(() =>
|
||||
view.animate({
|
||||
height: originalHeight,
|
||||
duration: animationDuration,
|
||||
})
|
||||
)
|
||||
.catch((err) => {
|
||||
console.error('animation error', err);
|
||||
});
|
||||
} else {
|
||||
view
|
||||
.animate({
|
||||
opacity: this._selectedAnimation === 'opacity' ? 0 : 1,
|
||||
scale: this._selectedAnimation === 'scale' ? { x: 0.5, y: 0.6 } : { x: 1, y: 1 },
|
||||
rotate: this._selectedAnimation === 'rotate' ? 180 : 0,
|
||||
translate: this._selectedAnimation === 'translate' ? { x: 100, y: 100 } : { x: 0, y: 0 },
|
||||
duration: 500,
|
||||
})
|
||||
.then(() =>
|
||||
view.animate({
|
||||
opacity: 1,
|
||||
scale: { x: 1, y: 1 },
|
||||
rotate: 0,
|
||||
translate: { x: 0, y: 0 },
|
||||
duration: 500,
|
||||
})
|
||||
)
|
||||
.catch((err) => {
|
||||
console.error('animation error', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
179
apps/toolbox/src/box-shadow.xml
Normal file
179
apps/toolbox/src/box-shadow.xml
Normal file
@ -0,0 +1,179 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Dev Toolbox" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="*, auto, *" class="box-shadow-demo">
|
||||
<StackLayout backgroundColor="#ededed" row="0" padding="20" id="boxShadowDemo">
|
||||
<!-- layouts -->
|
||||
<ScrollView height="100%" visibility="{{ selectedComponentType === 'layouts' ? 'visible' : 'collapsed' }}">
|
||||
<StackLayout>
|
||||
<StackLayout
|
||||
width="300"
|
||||
height="100"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
>
|
||||
<Label text="StackLayout"></Label>
|
||||
</StackLayout>
|
||||
|
||||
<GridLayout
|
||||
width="300"
|
||||
height="100"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
>
|
||||
<Label text="GridLayout"></Label>
|
||||
</GridLayout>
|
||||
|
||||
<AbsoluteLayout
|
||||
width="300"
|
||||
height="100"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
>
|
||||
<Label text="AbsoluteLayout"></Label>
|
||||
</AbsoluteLayout>
|
||||
|
||||
<DockLayout
|
||||
width="300"
|
||||
height="100"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
>
|
||||
<Label text="DockLayout"></Label>
|
||||
</DockLayout>
|
||||
|
||||
<FlexboxLayout
|
||||
width="300"
|
||||
height="100"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
>
|
||||
<Label text="FlexboxLayout"></Label>
|
||||
</FlexboxLayout>
|
||||
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
||||
<!-- labels -->
|
||||
<GridLayout
|
||||
rows="*"
|
||||
height="100%"
|
||||
visibility="{{ selectedComponentType === 'labels' ? 'visible' : 'collapsed' }}">
|
||||
|
||||
<Label
|
||||
horizontalAlignment="center"
|
||||
verticalAlignment="center"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
text="Label"></Label>
|
||||
|
||||
</GridLayout>
|
||||
|
||||
<!-- buttons -->
|
||||
<GridLayout
|
||||
rows="*"
|
||||
height="100%"
|
||||
visibility="{{ selectedComponentType === 'buttons' ? 'visible' : 'collapsed' }}">
|
||||
|
||||
<Button
|
||||
horizontalAlignment="center"
|
||||
verticalAlignment="center"
|
||||
class="demo-component"
|
||||
boxShadow="{{ appliedBoxShadow }}"
|
||||
borderWidth="{{ borderWidth }}"
|
||||
borderRadius="{{ borderRadius }}"
|
||||
background="{{ background }}"
|
||||
tap="{{ toggleAnimation }}"
|
||||
text="button"
|
||||
></Button>
|
||||
|
||||
</GridLayout>
|
||||
|
||||
</StackLayout>
|
||||
|
||||
<GridLayout
|
||||
row="1"
|
||||
rows="auto"
|
||||
columns="auto, *, auto"
|
||||
class="box-shadow-prop-controls">
|
||||
<Label
|
||||
col="0"
|
||||
verticalAlignment="center"
|
||||
text="box-shadow:"></Label>
|
||||
<TextField
|
||||
col="1"
|
||||
placeholder="box-shadow"
|
||||
textChange="{{ textChange }}"
|
||||
>
|
||||
</TextField>
|
||||
<Button
|
||||
col="2"
|
||||
text="APPLY"
|
||||
class="btn-apply"
|
||||
tap="{{ applyBoxShadow }}"></Button>
|
||||
</GridLayout>
|
||||
<ScrollView row="2">
|
||||
<StackLayout padding="10" class="controls">
|
||||
<Label text="Components"></Label>
|
||||
<FlexboxLayout flexDirection="row" flexWrap="wrap">
|
||||
<Button text="Layouts" componentType="layouts" tap="{{ selectComponentType }}"></Button>
|
||||
<Button text="Labels" componentType="labels" selectedAttr="{{ selectedComponentType }}" tap="{{ selectComponentType }}"></Button>
|
||||
<Button text="Buttons" componentType="buttons" selectedAttr="{{ selectedComponentType == 'buttons' }}" tap="{{ selectComponentType }}"></Button>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label text="Background"></Label>
|
||||
<FlexboxLayout flexDirection="row" flexWrap="wrap">
|
||||
<Button text="Solid" backgroundType="solid" tap="{{ selectBackgroundType }}"></Button>
|
||||
<Button text="Transparent" backgroundType="transparent" tap="{{ selectBackgroundType }}"></Button>
|
||||
<Button text="Gradient" backgroundType="gradient" tap="{{ selectBackgroundType }}"></Button>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label text="Borders"></Label>
|
||||
<FlexboxLayout flexDirection="row" flexWrap="wrap">
|
||||
<Button text="Solid" borderType="solid" tap="{{ selectBorderType }}"></Button>
|
||||
<Button text="Rounded" borderType="rounded" tap="{{ selectBorderType }}"></Button>
|
||||
<Button text="None" borderType="none" tap="{{ selectBorderType }}"></Button>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label text="Animations"></Label>
|
||||
<Label text="Tap on the component to start and stop animation" class="description"></Label>
|
||||
<FlexboxLayout flexDirection="row" flexWrap="wrap">
|
||||
<Button text="Width" animationType="width" tap="{{ selectAnimationType }}"></Button>
|
||||
<Button text="Height" animationType="height" tap="{{ selectAnimationType }}"></Button>
|
||||
<Button text="Opacity" animationType="opacity" tap="{{ selectAnimationType }}"></Button>
|
||||
<Button text="Translate" animationType="translate" tap="{{ selectAnimationType }}"></Button>
|
||||
<Button text="Scale" animationType="scale" tap="{{ selectAnimationType }}"></Button>
|
||||
<Button text="Rotate" animationType="rotate" tap="{{ selectAnimationType }}"></Button>
|
||||
</FlexboxLayout>
|
||||
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</GridLayout>
|
||||
</Page>
|
@ -1,86 +1,15 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Dev Toolbox" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="2*, *">
|
||||
<!-- background color transparent here to hide children overflow -->
|
||||
<AbsoluteLayout row="0" backgroundColor="transparent">
|
||||
<!-- Root layout demo -->
|
||||
<RootLayout height="100%" width="100%">
|
||||
<GridLayout height="100%" backgroundColor="#232652">
|
||||
<Label verticalAlignment="center" textAlignment="center" fontWeight="bold" color="#fff" text="ROOT LAYOUT CONTENT"></Label>
|
||||
</GridLayout>
|
||||
</RootLayout>
|
||||
</AbsoluteLayout>
|
||||
|
||||
<!-- Root layout controls -->
|
||||
<StackLayout row="1">
|
||||
<ScrollView height="100%">
|
||||
<StackLayout class="p-15">
|
||||
<Label color="#b4b6b9" fontSize="25" fontWeight="bold" text="ORANGE"></Label>
|
||||
<FlexboxLayout flexDirection="row" justifyContent="space-between">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="0" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="0" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="0" class="btn btn-primary btn-active"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label color="#b4b6b9" fontSize="25" fontWeight="bold" text="NAVY"></Label>
|
||||
<FlexboxLayout flexDirection="row">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="1" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="1" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="1" class="btn btn-primary btn-active"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label color="#b4b6b9" fontSize="25" fontWeight="bold" text="GRAY"></Label>
|
||||
<FlexboxLayout flexDirection="row">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="2" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="2" class="btn btn-primary btn-active"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="2" class="btn btn-primary btn-active"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
<!-- <Button text="Button with html boxShadow" tap="{{ onTap }}" height="50" class="btn btn-primary btn-active" boxShadow="5 5 10 navy"/>
|
||||
|
||||
<Button text="Button with css boxShadow (rgba)" tap="{{ onTap }}" height="50" marginTop="50" class="btn btn-primary btn-active"/>
|
||||
|
||||
<Button text="Button with boxShadow 3 props" tap="{{ onTap }}" height="50" marginTop="50" boxShadow="5 5 navy" class="btn btn-primary btn-active"/>
|
||||
<Button text="Button with boxShadow 4 props" tap="{{ onTap }}" height="50" marginTop="50" boxShadow="5 5 10 navy" class="btn btn-primary btn-active"/>
|
||||
<Button text="Button with boxShadow 5 props" tap="{{ onTap }}" height="50" marginTop="50" boxShadow="5 5 10 10 navy" class="btn btn-primary btn-active"/>
|
||||
|
||||
<StackLayout boxShadow="10 10 rgba(0,0,0,1)" marginTop="50">
|
||||
<Button text="Button with css boxShadow" tap="{{ onTap }}" height="50" borderRadius="10"/>
|
||||
</StackLayout> -->
|
||||
|
||||
<!-- TODO: if backgroundColor is not set, it won't call background.ios.ts hence not applying the boxShadow -->
|
||||
<!-- <StackLayout boxShadow="5 5 10 10 red" height="100" backgroundColor="transparent" padding="10" margin="20">
|
||||
<Label text="StackLayout with transparent background"></Label>
|
||||
</StackLayout> -->
|
||||
|
||||
<GridLayout boxShadow="10 -10 10 10 rgba(0,0,0,0.5)" height="100" backgroundColor="lightblue" padding="10" margin="20" tap="{{ toggleAnimation }}">
|
||||
<Label text="GridLayout"></Label>
|
||||
</GridLayout>
|
||||
|
||||
<StackLayout boxShadow="5 10 10 20 #000" height="100" backgroundColor="lightblue" padding="10" margin="20" tap="{{ toggleAnimation }}">
|
||||
<Label text="StackLayout"></Label>
|
||||
</StackLayout>
|
||||
|
||||
<AbsoluteLayout boxShadow="5 15 10 20 green" height="100" backgroundColor="lightblue" padding="10" margin="20" tap="{{ toggleAnimation }}">
|
||||
<Label text="AbsoluteLayout"></Label>
|
||||
</AbsoluteLayout>
|
||||
|
||||
<!-- note: the 3rd number in box shadow is currently being ignored, only the 1st, 2nd, and 4th, and color are being used-->
|
||||
<FlexboxLayout boxShadow="0 0 10 25 red" height="100" backgroundColor="lightblue" padding="10" margin="20" tap="{{ toggleAnimation }}">
|
||||
<Label text="FlexboxLayout"></Label>
|
||||
</FlexboxLayout>
|
||||
|
||||
<FlexboxLayout boxShadow="15 10 10 20 #000" height="100" backgroundColor="transparent" padding="10" margin="20" tap="{{ toggleAnimation }}">
|
||||
<Label text="FlexboxLayout (transparent background)"></Label>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Button marginTop="30" boxShadow="0 0 10 8 #000" backgroundColor="transparent" text="button" padding="20"></Button>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Dev Toolbox" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
<StackLayout class="p-20">
|
||||
<ScrollView class="h-full">
|
||||
<StackLayout>
|
||||
<Button text="list-page" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo"/>
|
||||
<Button text="box-shadow" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo"/>
|
||||
<Button text="root-layout" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo"/>
|
||||
</StackLayout>
|
||||
</GridLayout>
|
||||
</ScrollView>
|
||||
</StackLayout>
|
||||
</Page>
|
||||
|
@ -1,171 +1,9 @@
|
||||
import { Observable, Frame, View, StackLayout, getRootLayout, EventData, RootLayout, RootLayoutOptions } from '@nativescript/core';
|
||||
import { AnimationCurve } from '@nativescript/core/ui/enums';
|
||||
import { Observable, Frame } from '@nativescript/core';
|
||||
|
||||
export class HelloWorldModel extends Observable {
|
||||
private _counter: number;
|
||||
private _message: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// Initialize default values.
|
||||
this._counter = 42;
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
get message(): string {
|
||||
return this._message;
|
||||
}
|
||||
|
||||
set message(value: string) {
|
||||
if (this._message !== value) {
|
||||
this._message = value;
|
||||
this.notifyPropertyChange('message', value);
|
||||
}
|
||||
}
|
||||
|
||||
toggleAnimation(args) {
|
||||
const layout = args.object as StackLayout;
|
||||
if (!layout.className) {
|
||||
layout.className = 'sample-animation';
|
||||
} else {
|
||||
layout.className = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
onTap() {
|
||||
this._counter--;
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
popupViews: { view: View; options: RootLayoutOptions; extra?: any }[] = [
|
||||
{
|
||||
view: this.getPopup('#EA5936', 110, -30),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: '#FFF',
|
||||
opacity: 0.7,
|
||||
tapToClose: true,
|
||||
},
|
||||
animation: {
|
||||
enterFrom: {
|
||||
opacity: 0,
|
||||
translateY: 500,
|
||||
duration: 500,
|
||||
},
|
||||
exitTo: {
|
||||
opacity: 0,
|
||||
duration: 300,
|
||||
},
|
||||
},
|
||||
},
|
||||
extra: {
|
||||
customExitAnimation: {
|
||||
opacity: 0,
|
||||
translate: { x: 0, y: -500 },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
view: this.getPopup('#232652', 110, 0),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: 'pink',
|
||||
opacity: 0.7,
|
||||
tapToClose: false,
|
||||
animation: {
|
||||
exitTo: {
|
||||
scaleX: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
view: this.getPopup('#E1E4E8', 110, 30),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: '#ffffdd',
|
||||
opacity: 0.5,
|
||||
tapToClose: true,
|
||||
ignoreShadeRestore: true,
|
||||
animation: {
|
||||
enterFrom: {
|
||||
translateX: -1000,
|
||||
duration: 500,
|
||||
},
|
||||
exitTo: {
|
||||
rotate: -180,
|
||||
duration: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
enterFrom: {
|
||||
rotate: 180,
|
||||
duration: 300,
|
||||
},
|
||||
exitTo: {
|
||||
rotate: 180,
|
||||
opacity: 0,
|
||||
duration: 300,
|
||||
curve: AnimationCurve.spring,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
open(args: EventData): void {
|
||||
getRootLayout()
|
||||
.open(this.popupViews[(<any>args.object).popupIndex].view, this.popupViews[(<any>args.object).popupIndex].options)
|
||||
.then(() => console.log('opened'))
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
|
||||
bringToFront(args: EventData): void {
|
||||
getRootLayout()
|
||||
.bringToFront(this.popupViews[(<any>args.object).popupIndex].view, true)
|
||||
.then(() => console.log('brought to front'))
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
|
||||
close(args: EventData): void {
|
||||
if (this.popupViews[(<any>args.object).popupIndex]?.extra?.customExitAnimation) {
|
||||
getRootLayout()
|
||||
.close(this.popupViews[(<any>args.object).popupIndex].view, this.popupViews[(<any>args.object).popupIndex].extra.customExitAnimation)
|
||||
.then(() => console.log('closed with custom exit animation'))
|
||||
.catch((ex) => console.error(ex));
|
||||
} else {
|
||||
getRootLayout()
|
||||
.close(this.popupViews[(<any>args.object).popupIndex].view)
|
||||
.then(() => console.log('closed'))
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
getPopup(color: string, size: number, offset: number): View {
|
||||
const layout = new StackLayout();
|
||||
layout.height = size;
|
||||
layout.width = size;
|
||||
layout.marginTop = offset;
|
||||
layout.marginLeft = offset;
|
||||
layout.backgroundColor = color;
|
||||
layout.borderRadius = 10;
|
||||
return layout;
|
||||
}
|
||||
|
||||
viewList() {
|
||||
viewDemo(args) {
|
||||
Frame.topmost().navigate({
|
||||
moduleName: 'list-page',
|
||||
moduleName: `${args.object.text}`,
|
||||
});
|
||||
}
|
||||
|
||||
private updateMessage() {
|
||||
if (this._counter <= 0) {
|
||||
this.message = 'Hoorraaay! You unlocked the NativeScript clicker achievement!';
|
||||
} else {
|
||||
this.message = `${this._counter} taps left`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
122
apps/toolbox/src/root-layout.ts
Normal file
122
apps/toolbox/src/root-layout.ts
Normal file
@ -0,0 +1,122 @@
|
||||
import { EventData, Page, Observable, RootLayoutOptions, getRootLayout, StackLayout, View } from '@nativescript/core';
|
||||
import { AnimationCurve } from '@nativescript/core/ui/enums';
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
const page = <Page>args.object;
|
||||
page.bindingContext = new BoxShadowModel();
|
||||
}
|
||||
|
||||
export class BoxShadowModel extends Observable {
|
||||
popupViews: { view: View; options: RootLayoutOptions; extra?: any }[] = [
|
||||
{
|
||||
view: this.getPopup('#EA5936', 110, -30),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: '#FFF',
|
||||
opacity: 0.7,
|
||||
tapToClose: true,
|
||||
},
|
||||
animation: {
|
||||
enterFrom: {
|
||||
opacity: 0,
|
||||
translateY: 500,
|
||||
duration: 500,
|
||||
},
|
||||
exitTo: {
|
||||
opacity: 0,
|
||||
duration: 300,
|
||||
},
|
||||
},
|
||||
},
|
||||
extra: {
|
||||
customExitAnimation: {
|
||||
opacity: 0,
|
||||
translate: { x: 0, y: -500 },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
view: this.getPopup('#232652', 110, 0),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: 'pink',
|
||||
opacity: 0.7,
|
||||
tapToClose: false,
|
||||
animation: {
|
||||
exitTo: {
|
||||
scaleX: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
view: this.getPopup('#E1E4E8', 110, 30),
|
||||
options: {
|
||||
shadeCover: {
|
||||
color: '#ffffdd',
|
||||
opacity: 0.5,
|
||||
tapToClose: true,
|
||||
ignoreShadeRestore: true,
|
||||
animation: {
|
||||
enterFrom: {
|
||||
translateX: -1000,
|
||||
duration: 500,
|
||||
},
|
||||
exitTo: {
|
||||
rotate: -180,
|
||||
duration: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
enterFrom: {
|
||||
rotate: 180,
|
||||
duration: 300,
|
||||
},
|
||||
exitTo: {
|
||||
rotate: 180,
|
||||
opacity: 0,
|
||||
duration: 300,
|
||||
curve: AnimationCurve.spring,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
open(args: EventData): void {
|
||||
getRootLayout()
|
||||
.open(this.popupViews[(<any>args.object).popupIndex].view, this.popupViews[(<any>args.object).popupIndex].options)
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
|
||||
bringToFront(args: EventData): void {
|
||||
getRootLayout()
|
||||
.bringToFront(this.popupViews[(<any>args.object).popupIndex].view, true)
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
|
||||
close(args: EventData): void {
|
||||
if (this.popupViews[(<any>args.object).popupIndex]?.extra?.customExitAnimation) {
|
||||
getRootLayout()
|
||||
.close(this.popupViews[(<any>args.object).popupIndex].view, this.popupViews[(<any>args.object).popupIndex].extra.customExitAnimation)
|
||||
.catch((ex) => console.error(ex));
|
||||
} else {
|
||||
getRootLayout()
|
||||
.close(this.popupViews[(<any>args.object).popupIndex].view)
|
||||
.catch((ex) => console.error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
getPopup(color: string, size: number, offset: number): View {
|
||||
const layout = new StackLayout();
|
||||
layout.height = size;
|
||||
layout.width = size;
|
||||
layout.marginTop = offset;
|
||||
layout.marginLeft = offset;
|
||||
layout.backgroundColor = color;
|
||||
layout.borderRadius = 10;
|
||||
return layout;
|
||||
}
|
||||
}
|
47
apps/toolbox/src/root-layout.xml
Normal file
47
apps/toolbox/src/root-layout.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Dev Toolbox" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="2*, *">
|
||||
<!-- background color transparent here to hide children overflow -->
|
||||
<AbsoluteLayout row="0" backgroundColor="transparent">
|
||||
<!-- Root layout demo -->
|
||||
<RootLayout height="100%" width="100%">
|
||||
<GridLayout height="100%" backgroundColor="#ededed">
|
||||
<Label verticalAlignment="center" textAlignment="center" fontWeight="bold" color="#333" text="ROOT LAYOUT CONTENT"></Label>
|
||||
</GridLayout>
|
||||
</RootLayout>
|
||||
</AbsoluteLayout>
|
||||
|
||||
<!-- Root layout controls -->
|
||||
<StackLayout row="1">
|
||||
<ScrollView height="100%">
|
||||
<StackLayout padding="20" class="controls">
|
||||
<Label text="ORANGE"></Label>
|
||||
<FlexboxLayout flexDirection="row" justifyContent="space-between">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="0"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="0"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="0"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label text="NAVY"></Label>
|
||||
<FlexboxLayout flexDirection="row" justifyContent="space-between">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="1"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="1"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="1"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
<Label text="GRAY"></Label>
|
||||
<FlexboxLayout flexDirection="row" justifyContent="space-between">
|
||||
<Button flexGrow="1" text="open" tap="{{ open }}" popupIndex="2"/>
|
||||
<Button flexGrow="1" text="front" tap="{{ bringToFront }}" popupIndex="2"/>
|
||||
<Button flexGrow="1" text="close" tap="{{ close }}" popupIndex="2"/>
|
||||
</FlexboxLayout>
|
||||
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</StackLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
@ -95,7 +95,7 @@ export namespace ad {
|
||||
|
||||
const boxShadow = view.style.boxShadow;
|
||||
if (boxShadow) {
|
||||
drawBoxShadow(nativeView, boxShadow);
|
||||
drawBoxShadow(nativeView, view, boxShadow);
|
||||
}
|
||||
|
||||
// TODO: Can we move BorderWidths as separate native setter?
|
||||
@ -226,15 +226,14 @@ function createNativeCSSValueArray(css: string): native.Array<org.nativescript.w
|
||||
return nativeArray;
|
||||
}
|
||||
|
||||
function drawBoxShadow(nativeView: android.view.View, boxShadow: BoxShadow) {
|
||||
function drawBoxShadow(nativeView: android.view.View, view: View, boxShadow: BoxShadow) {
|
||||
const color = boxShadow.color;
|
||||
const shadowOpacity = color.a;
|
||||
const shadowColor = new Color(shadowOpacity, color.r, color.g, color.b);
|
||||
// TODO: corner radius here should reflect the view's corner radius
|
||||
const cornerRadius = 0; // this should be applied to the main view as well (try 20 with a transparent background on the xml to see the effect)
|
||||
const cornerRadius = view.borderRadius; // this should be applied to the main view as well (try 20 with a transparent background on the xml to see the effect)
|
||||
const config = {
|
||||
shadowColor: shadowColor.android,
|
||||
cornerRadius,
|
||||
cornerRadius: cornerRadius,
|
||||
spreadRadius: boxShadow.spreadRadius,
|
||||
blurRadius: boxShadow.blurRadius,
|
||||
offsetX: boxShadow.offsetX,
|
||||
|
@ -8,8 +8,6 @@ import { isDataURI, isFileOrResourcePath, layout } from '../../utils';
|
||||
import { ImageSource } from '../../image-source';
|
||||
import { CSSValue, parse as cssParse } from '../../css-value';
|
||||
import { BoxShadow } from './box-shadow';
|
||||
import { Screen } from '../../platform';
|
||||
import { StackLayout } from '../layouts/stack-layout';
|
||||
|
||||
export * from './background-common';
|
||||
|
||||
@ -92,11 +90,10 @@ export namespace ios {
|
||||
|
||||
const boxShadow = view.style.boxShadow;
|
||||
if (boxShadow) {
|
||||
|
||||
// this is required (if not, shadow will get cutoff at parent's dimensions)
|
||||
// nativeView.clipsToBounds doesn't work
|
||||
view.setProperty('clipToBounds', false);
|
||||
drawBoxShadow(nativeView, boxShadow, background);
|
||||
drawBoxShadow(nativeView, view, boxShadow, background);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -720,40 +717,29 @@ function drawNoRadiusNonUniformBorders(nativeView: NativeView, background: Backg
|
||||
}
|
||||
|
||||
// TODO: use sublayer if its applied to a layout
|
||||
function drawBoxShadow(nativeView: NativeView, boxShadow: BoxShadow, background: BackgroundDefinition, useSubLayer: boolean = false) {
|
||||
function drawBoxShadow(nativeView: NativeView, view: View, boxShadow: BoxShadow, background: BackgroundDefinition, useSubLayer: boolean = false) {
|
||||
const layer: CALayer = nativeView.layer;
|
||||
|
||||
layer.masksToBounds = false;
|
||||
nativeView.clipsToBounds = false;
|
||||
|
||||
if (!background.color.a) {
|
||||
if (!background.color?.a) {
|
||||
// add white background if view has a transparent background
|
||||
layer.backgroundColor = UIColor.whiteColor.CGColor;
|
||||
}
|
||||
// shadow opacity is handled on the shadow's color instance
|
||||
layer.shadowOpacity = 1;
|
||||
layer.shadowRadius = boxShadow.spreadRadius;
|
||||
layer.shadowRadius = layout.toDeviceIndependentPixels(boxShadow.spreadRadius);
|
||||
layer.shadowColor = boxShadow.color.ios.CGColor;
|
||||
|
||||
// / 2 here since ios's shadow offset is bigger than android
|
||||
// TODO: this is just for experimenting with the amount of offset,
|
||||
// need to use some real calculation here to gain parity with android's
|
||||
// implementation
|
||||
const adjustedShadowOffset = {
|
||||
x: boxShadow.offsetX / 2,
|
||||
y: boxShadow.offsetY / 2,
|
||||
x: layout.toDeviceIndependentPixels(boxShadow.offsetX),
|
||||
y: layout.toDeviceIndependentPixels(boxShadow.offsetY),
|
||||
};
|
||||
layer.shadowOffset = CGSizeMake(adjustedShadowOffset.x, adjustedShadowOffset.y);
|
||||
|
||||
// this should match the view's border radius
|
||||
const cornerRadius = 0;
|
||||
// This doesn't handle the offsets properly
|
||||
// factor in shadowRadius and the offsets so shadow don't spread too far
|
||||
// layer.shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(CGRectMake(
|
||||
// nativeView.bounds.origin.x + boxShadow.spreadRadius + adjustedShadowOffset.x,
|
||||
// nativeView.bounds.origin.y + boxShadow.spreadRadius + adjustedShadowOffset.y,
|
||||
// nativeView.bounds.size.width - boxShadow.spreadRadius - adjustedShadowOffset.x,
|
||||
// nativeView.bounds.size.height - boxShadow.spreadRadius - adjustedShadowOffset.y), cornerRadius).CGPath;
|
||||
const cornerRadius = 0; // layout.toDeviceIndependentPixels(view.style.borderRadius);
|
||||
|
||||
// This has the nice glow with box shadow of 0,0
|
||||
layer.shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(nativeView.bounds, cornerRadius).CGPath;
|
||||
|
Reference in New Issue
Block a user