Skip to content

Commit dd4c4aa

Browse files
committed
Merge pull request #936 from NativeScript/cankov/animate-transform-sequence
Subsequent animation of transition and rotation or scale will appear jumpy in iOS
2 parents 729bed9 + 9757bc5 commit dd4c4aa

File tree

4 files changed

+148
-63
lines changed

4 files changed

+148
-63
lines changed

apps/animations/main-page.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,75 @@ export function onSingle(args: observable.EventData) {
9090
})
9191
.then(() => console.log("Animation finished"))
9292
.catch((e) => console.log(e.message));
93+
}
94+
95+
export function onSequence(args: observable.EventData) {
96+
console.log("onSequence");
97+
98+
button3.animate({
99+
translate: { x: 80, y: -40 },
100+
scale: { x: 0.9, y: 0.3 },
101+
rotate: 25,
102+
duration: 1000
103+
})
104+
.then(() => button3.animate({
105+
translate: { x: 0, y: -80 },
106+
scale: { x: 0.5, y: 0.5 },
107+
rotate: -25,
108+
duration: 1000
109+
}))
110+
.then(() => button3.animate({
111+
translate: { x: -80, y: -40 },
112+
scale: { x: 0.5, y: 0.9 },
113+
rotate: 45,
114+
duration: 1000
115+
}))
116+
.then(() => button3.animate({
117+
translate: { x: 0, y: 0 },
118+
scale: { x: 1, y: 1 },
119+
rotate: 0,
120+
duration: 1000
121+
}))
122+
.then(() => console.log("Animation finished"))
123+
.catch((e) => console.log(e.message));
124+
}
125+
126+
export function onInterrupted(args: observable.EventData) {
127+
console.log("onInterrupt");
128+
129+
setTimeout(() => {
130+
button3.animate({
131+
translate: { x: 80, y: -40 },
132+
scale: { x: 0.9, y: 0.3 },
133+
rotate: 25,
134+
duration: 1000
135+
});
136+
}, 700 * 0);
137+
138+
setTimeout(function() {
139+
button3.animate({
140+
translate: { x: 0, y: -80 },
141+
scale: { x: 0.5, y: 0.5 },
142+
rotate: -25,
143+
duration: 1000
144+
})
145+
}, 700 * 1);
146+
147+
setTimeout(function() {
148+
button3.animate({
149+
translate: { x: -80, y: -40 },
150+
scale: { x: 0.5, y: 0.9 },
151+
rotate: 45,
152+
duration: 1000
153+
})
154+
}, 700 * 2);
155+
156+
setTimeout(function() {
157+
button3.animate({
158+
translate: { x: 0, y: 0 },
159+
scale: { x: 1, y: 1 },
160+
rotate: 0,
161+
duration: 1000
162+
})
163+
}, 700 * 3);
93164
}

apps/animations/main-page.xml

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,34 @@
22
<StackLayout orientation="vertical">
33
<StackLayout orientation="vertical" backgroundColor="LightGray" paddingTop="5" paddingBottom="5">
44

5-
<Label text="{{ duration, 'Duration: ' + duration + ' ms' }}" width="180" marginTop="5" marginBottom="5"/>
6-
<Slider minValue="0" maxValue="10000" value="{{ duration }}" marginTop="5" marginBottom="5" marginLeft="10" marginRight="10"/>
5+
<Label text="{{ duration, 'Duration: ' + duration + ' ms' }}" width="180" />
6+
<Slider minValue="0" maxValue="10000" value="{{ duration }}" margin="0 15" />
77

8-
<Label text="{{ iterations, 'Iterations: ' + iterations + ' times' }}" width="180" marginTop="5" marginBottom="5"/>
9-
<Slider minValue="0" maxValue="10" value="{{ iterations }}" marginTop="5" marginBottom="5" marginLeft="10" marginRight="10"/>
8+
<Label text="{{ iterations, 'Iterations: ' + iterations + ' times' }}" width="180" />
9+
<Slider minValue="0" maxValue="10" value="{{ iterations }}" margin="0 15" />
1010

11-
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center">
11+
<StackLayout orientation="horizontal" horizontalAlignment="center">
1212
<Label text="Play Sequentially?"/>
1313
<Switch marginLeft="10" checked="{{ playSequentially }}"/>
1414
</StackLayout>
15-
15+
1616
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center" paddingLeft="5" paddingRight="5">
17-
<Button text="Out" tap="onSlideOut" width="75" marginLeft="5" marginRight="5" />
18-
<Button text="In" tap="onSlideIn" width="75" marginLeft="5" marginRight="5" />
19-
<Button text="Single" tap="onSingle" width="75" marginLeft="5" marginRight="5" />
20-
<Button text="Cancel" tap="onCancel" width="75" marginLeft="5" marginRight="5" />
17+
<Button text="Out" tap="onSlideOut" width="40" marginLeft="5" marginRight="5" />
18+
<Button text="In" tap="onSlideIn" width="40" marginLeft="5" marginRight="5" />
19+
<Button text="Single" tap="onSingle" width="70" marginLeft="5" marginRight="5" />
20+
<Button text="Cancel" tap="onCancel" width="70" marginLeft="5" marginRight="5" />
2121
</StackLayout>
22-
22+
23+
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center" paddingLeft="5" paddingRight="5">>
24+
<Button text="Sequence" width="80" marginLeft="5" marginRight="5" tap="onSequence" />
25+
<Button text="Interrupted" width="80" marginLeft="5" marginRight="5" tap="onInterrupted" />
26+
</StackLayout>
27+
2328
</StackLayout>
2429
<AbsoluteLayout id="panel1" backgroundColor="Yellow" width="300" height="190" clipToBounds="true" marginTop="10">
25-
<Button id="button1" text="Button 1" backgroundColor="White" width="180" height="50" left="60" top="10" tap="onTap"/>
26-
<Button id="button2" text="Button 2" backgroundColor="White" width="180" height="50" left="60" top="70" tap="onTap"/>
27-
<Button id="button3" text="Button 3" backgroundColor="White" width="180" height="50" left="60" top="130" tap="onTap"/>
30+
<Button id="button1" text="Button 1" backgroundColor="White" width="180" height="50" left="60" top="10" tap="onTap" borderWidth="1" borderColor="red" />
31+
<Button id="button2" text="Button 2" backgroundColor="White" width="180" height="50" left="60" top="70" tap="onTap" borderWidth="1" borderColor="red" />
32+
<Button id="button3" text="Button 3" backgroundColor="White" width="180" height="50" left="60" top="130" tap="onTap" borderWidth="1" borderColor="red" />
2833
</AbsoluteLayout>
2934
</StackLayout>
30-
</Page>
35+
</Page>

tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@
336336
"./timer/timer.ios.ts",
337337
"./trace/trace.d.ts",
338338
"./trace/trace.ts",
339+
"./ui/animation/animation-common.ts",
340+
"./ui/animation/animation.android.ts",
341+
"./ui/animation/animation.ios.ts",
339342
"./ui/activity-indicator/activity-indicator-common.ts",
340343
"./ui/activity-indicator/activity-indicator.android.ts",
341344
"./ui/activity-indicator/activity-indicator.d.ts",

ui/animation/animation.ios.ts

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -168,59 +168,65 @@ export class Animation extends common.Animation implements definition.Animation
168168
}
169169

170170
trace.write("UIView.beginAnimationsContext(" + index + "): " + common.Animation._getAnimationInfo(animation), trace.categories.Animation);
171-
UIView.beginAnimationsContext(index.toString(), null);
172171

173-
if (animationDelegate) {
174-
UIView.setAnimationDelegate(animationDelegate);
175-
UIView.setAnimationWillStartSelector("animationWillStart");
176-
UIView.setAnimationDidStopSelector("animationDidStop");
177-
}
172+
UIView.animateKeyframesWithDurationDelayOptionsAnimationsCompletion(1, 0,
173+
UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionBeginFromCurrentState,
174+
() => {
175+
UIView.addKeyframeWithRelativeStartTimeRelativeDurationAnimations(0, 1, () => {
176+
if (animationDelegate) {
177+
UIView.setAnimationDelegate(animationDelegate);
178+
UIView.setAnimationWillStartSelector("animationWillStart");
179+
UIView.setAnimationDidStopSelector("animationDidStop");
180+
}
178181

179-
if (animation.duration !== undefined) {
180-
UIView.setAnimationDuration(animation.duration / 1000.0);
181-
}
182-
else {
183-
UIView.setAnimationDuration(0.3); //Default duration.
184-
}
185-
if (animation.delay !== undefined) {
186-
UIView.setAnimationDelay(animation.delay / 1000.0);
187-
}
188-
if (animation.iterations !== undefined) {
189-
if (animation.iterations === Number.POSITIVE_INFINITY) {
190-
UIView.setAnimationRepeatCount(FLT_MAX);
191-
}
192-
else {
193-
UIView.setAnimationRepeatCount(animation.iterations - 1);
194-
}
195-
}
196-
if (animation.curve !== undefined) {
197-
UIView.setAnimationCurve(animation.curve);
198-
}
182+
if (animation.duration !== undefined) {
183+
UIView.setAnimationDuration(animation.duration / 1000.0);
184+
}
185+
else {
186+
UIView.setAnimationDuration(0.3); //Default duration.
187+
}
188+
if (animation.delay !== undefined) {
189+
UIView.setAnimationDelay(animation.delay / 1000.0);
190+
}
191+
if (animation.iterations !== undefined) {
192+
if (animation.iterations === Number.POSITIVE_INFINITY) {
193+
UIView.setAnimationRepeatCount(FLT_MAX);
194+
}
195+
else {
196+
UIView.setAnimationRepeatCount(animation.iterations - 1);
197+
}
198+
}
199+
if (animation.curve !== undefined) {
200+
UIView.setAnimationCurve(animation.curve);
201+
}
199202

200-
var originalValue;
201-
switch (animation.property) {
202-
case common.Properties.opacity:
203-
originalValue = animation.target.opacity;
204-
(<any>animation)._propertyResetCallback = () => { animation.target.opacity = originalValue };
205-
animation.target.opacity = animation.value;
206-
break;
207-
case common.Properties.backgroundColor:
208-
originalValue = animation.target.backgroundColor;
209-
(<any>animation)._propertyResetCallback = () => { animation.target.backgroundColor = originalValue };
210-
animation.target.backgroundColor = animation.value;
211-
break;
212-
case _transform:
213-
originalValue = nativeView.transform;
214-
(<any>animation)._propertyResetCallback = () => { nativeView.transform = originalValue };
215-
nativeView.transform = Animation._createNativeAffineTransform(animation);
216-
break;
217-
default:
218-
throw new Error("Cannot animate " + animation.property);
219-
break;
220-
}
203+
var originalValue;
204+
switch (animation.property) {
205+
case common.Properties.opacity:
206+
originalValue = animation.target.opacity;
207+
(<any>animation)._propertyResetCallback = () => { animation.target.opacity = originalValue };
208+
animation.target.opacity = animation.value;
209+
break;
210+
case common.Properties.backgroundColor:
211+
originalValue = animation.target.backgroundColor;
212+
(<any>animation)._propertyResetCallback = () => { animation.target.backgroundColor = originalValue };
213+
animation.target.backgroundColor = animation.value;
214+
break;
215+
case _transform:
216+
originalValue = nativeView.transform;
217+
(<any>animation)._propertyResetCallback = () => { nativeView.transform = originalValue };
218+
nativeView.transform = Animation._createNativeAffineTransform(animation);
219+
break;
220+
default:
221+
throw new Error("Cannot animate " + animation.property);
222+
break;
223+
}
224+
})
225+
},
226+
null
227+
);
221228

222229
trace.write("UIView.commitAnimations " + index, trace.categories.Animation);
223-
UIView.commitAnimations();
224230

225231
if (!playSequentially && nextAnimationCallback) {
226232
nextAnimationCallback();

0 commit comments

Comments
 (0)