Animator
API Reference: UI.Animator
Animator is used to change the appearance of the UI objects with animation.
The components in the example are added from the code for better showcase purposes. To learn more about the subject you can refer to:
Adding Component From CodeAs a best practice, Smartface recommends using the WYSIWYG editor in order to add components and styles to your page or library. To learn how to use UI Editor better, please refer to this documentation
UI Editor Basicsimport PageSampleDesign from "generated/pages/pageSample";
import Application from "@smartface/native/application";
import Color from "@smartface/native/ui/color";
import View from "@smartface/native/ui/view";
import System from "@smartface/native/device/system";
import Button from "@smartface/native/ui/button";
import Animator from "@smartface/native/ui/animator";
import { withDismissAndBackButton } from "@smartface/mixins";
import { Route, Router } from "@smartface/router";
import { styleableComponentMixin } from "@smartface/styling-context";
class StyleableButton extends styleableComponentMixin(Button) {}
class StyleableView extends styleableComponentMixin(View) {}
//You should create new Page from UI-Editor and extend with it.
export default class AnimatorSample extends withDismissAndBackButton(PageSampleDesign) {
myView: StyleableView;
myButton: StyleableButton;
constructor(private router?: Router, private route?: Route) {
super({});
}
// The page design has been made from the code for better
// showcase purposes. As a best practice, remove this and
// use WYSIWYG editor to style your pages.
centerizeTheChildrenLayout() {
this.dispatch({
type: "updateUserStyle",
userStyle: {
flexProps: {
flexDirection: 'ROW',
justifyContent: 'CENTER',
alignItems: 'CENTER'
}
}
})
}
onShow() {
super.onShow();
const { headerBar } = System.OS === System.OSType.ANDROID ? this : this.parentController;
Application.statusBar.visible = false;
headerBar.visible = false;
}
onLoad() {
super.onLoad();
this.centerizeTheChildrenLayout();
this.myView = new StyleableView();
this.myButton = new StyleableButton({
text: "Animate",
onPress: (): void => {
this.myView.backgroundColor = Color.RED;
let animationRootView =
System.OS === System.OSType.IOS ? this.layout : this.myView.getParent();
Animator.animate(animationRootView, 5000, (): void => {
this.myView.left = 150;
this.myView.right = 150;
})
.then(2500, (): void => {
this.myView.left = 10;
this.myView.right = 10;
})
.complete((): void => {
this.myView.backgroundColor = Color.GREEN;
});
},
});
this.addChild(this.myView, "myView", ".sf-view", {
left: 10,
top: 10,
right: 10,
height: 100,
flexProps: {
positionType: "ABSOLUTE",
},
backgroundColor: "#008000",
});
this.addChild(this.myButton, "myButton", ".sf-button", {
left: 10,
top: 150,
right: 10,
height: 65,
flexProps: {
positionType: "ABSOLUTE",
},
backgroundColor: "#808080",
});
}
}
On iOS side, Animator is not working smoothly if it is applied to button object. We suggest using other UI elements for animations.
Best practices for selecting the perfect root
- On Android just pick the parent view
- On iOS, pick the most parent object. If the animating view is a direct descendant of the page, then select the
page.layout
or the view is within a ScrollView, then select thescrollView.layout
. The rule is simple, traverse to all the way to the parents, if there is no parent, use that view. So page.layout, scrollView.layout do not have any parents.
Limitations of the root view
A root view can handle one animation at a time. It is not possible to use different animate functions and providing same root view most likely to cause exception
View Animations
Views on the screen need to be repositioned. It is possible to animate the scale, position, rotation, and alpha of any type of View with View animations.
Moving Into Header Bar
View can have position on HeaderBar by means of Dialog and getScreenLocation() function for a View or a HeaderBarItem.
Android runs asynchronous on onShow() function of Dialog, so it must be animated onShow() function of Page. Dialog BackgroundColor must be set transparent on iOS.
The components in the example are added from the code for better showcase purposes. To learn more about the subject you can refer to:
Adding Component From CodeAs a best practice, Smartface recommends using the WYSIWYG editor in order to add components and styles to your page or library. To learn how to use UI Editor better, please refer to this documentation
UI Editor Basicsimport PageSampleDesign from "generated/pages/pageSample";
import Application from "@smartface/native/application";
import Color from "@smartface/native/ui/color";
import View from "@smartface/native/ui/view";
import System from "@smartface/native/device/system";
import Button from "@smartface/native/ui/button";
import Animator from "@smartface/native/ui/animator";
import ImageView from "@smartface/native/ui/imageview";
import HeaderBarItem from "@smartface/native/ui/headerbaritem";
import Dialog from "@smartface/native/ui/dialog";
import { withDismissAndBackButton } from "@smartface/mixins";
import { Route, Router } from "@smartface/router";
import { styleableComponentMixin } from "@smartface/styling-context";
class StyleableButton extends styleableComponentMixin(Button) {}
class StyleableImageView extends styleableComponentMixin(ImageView) {}
//You should create new Page from UI-Editor and extend with it.
export default class AnimatorSample extends withDismissAndBackButton(PageSampleDesign) {
myFlProd: StyleableImageView;
myButton: StyleableButton;
myFlCart: StyleableImageView;
headerBarItem: HeaderBarItem;
myDialog: Dialog;
animationRootView: View;
constructor(private router?: Router, private route?: Route) {
super({});
}
// The page design has been made from the code for better
// showcase purposes. As a best practice, remove this and
// use WYSIWYG editor to style your pages.
centerizeTheChildrenLayout() {
this.dispatch({
type: "updateUserStyle",
userStyle: {
flexProps: {
flexDirection: 'ROW',
justifyContent: 'CENTER',
alignItems: 'CENTER'
}
}
})
}
onShow() {
super.onShow();
const { headerBar } = System.OS === System.OSType.ANDROID ? this : this.parentController;
Application.statusBar.visible = true;
headerBar.visible = true;
this.myButton.onPress = (): void => {
this.myDialog.show();
if (System.OS === System.OSType.IOS) {
this.myDialog.layout.backgroundColor = Color.TRANSPARENT;
this.animate();
}
};
if (System.OS === System.OSType.ANDROID) {
this.animate();
}
}
animate(): void {
let itemPos = this.headerBarItem.getScreenLocation();
let itemSize = this.headerBarItem.size;
//@ts-ignore
let animationRootView =
System.OS === System.OSType.IOS ? this.myDialog.layout : this.myFlProd.getParent();
Animator.animate(animationRootView, 1200, (): void => {
this.myFlProd.top =
itemPos.y +
itemSize.height / 2 -
this.myFlProd.height / 2 -
(System.OS === System.OSType.ANDROID ? Application.statusBar.height : 0);
this.myFlProd.left =
itemPos.x + itemSize.width / 2 - this.myFlProd.width / 2;
this.myFlProd.scale = { x: 0.01, y: 0.01 };
}).complete((): void => {
this.myFlProd.visible = false;
this.myDialog.hide();
this.headerBarItem.badge.text = "1";
});
}
onLoad() {
super.onLoad();
this.centerizeTheChildrenLayout();
this.myButton = new StyleableButton({
text: "Add To Cart",
});
this.myFlProd = new StyleableImageView({
image: "images://bird.png", // Don't forget to generate your bird image
});
this.myFlCart = new StyleableImageView({
image: "images://bird.png",
});
this.headerBarItem = new HeaderBarItem({
title: "Cart",
color: Color.BLACK,
});
this.headerBar.setItems([this.headerBarItem]);
this.myDialog = new Dialog();
this.myDialog.android.isTransparent = true;
this.myDialog.layout.addChild(this.myFlProd);
this.animationRootView =
System.OS === System.OSType.IOS ? this.myDialog.layout : this.myFlProd.getParent();
this.addChild(this.myButton, "myButton", ".sf-button", {
width: 150,
height: 70,
backgroundColor: "#57A5CF",
top: 100,
left: 100,
});
this.addChild(this.myFlCart, "myFlCart", ".sf-imageView", {
width: 200,
height: 200,
top: 110,
left: 80,
});
}
}
Non-practical animations
There are several scenarios that animate can cause problems or may not work as intended.
ListView
Do not animate anything within the ListViewItem. ListView is re-using the objects. In that case, row rendering operations will conflict with the ongoing animations.
Non-size & Non-position
Animation works best with sizes and position affecting scenarios. Animating other properties might not result as expected (such as colors, texts)
SwipeView page change animations
Moving the page indicator with animation in a SwipeView to make a carousel display, can cause problems. The user is going to swipe the pages again before the animation is complete. In that case, another animation is about to start with using same root view.