I'm working on a collapsable component, one that you can click to roll-up/down to show/hide details. The component is as follows:
// component.ts
import {Component, Directive, Input} from '#angular/core';
import {trigger, state, style, transition, animate} from '#angular/core'
#Component({
selector: 'expandable',
template: '<div *ngIf="isExpanded" #animate="'slide'"><ng-content></ng-content></div>',
animations: [
trigger('animate', [
state('slide', style({ overflow: 'hidden', height: '*' })),
transition('slide => void', [animate('200ms ease-out', style({ height: 0 }))]),
transition('void => slide', [style({ height: 0 }), animate('200ms ease-out', style({ height: '*' }))])
])
]
})
export class SimExpandable {
private _expanded: boolean = false;
#Input('expanded') set expanded(value: string | boolean) {
this._expanded = (value === 'true' || value === true);
}
get isExpanded(): boolean { return this._expanded }
}
The component works fine, partially. The animations, however, are not perfect. I've configured the component to use ease-out animation but in reality, the component animates linearly.
I've tried using ease-out, easeOut, ease-out-cubic, easeOutCubic, ease-in-out, easeInOut, bounce, and a lot of other permutations but the component still animates linearly. I REALLY need to use ease-out for my component. Any help would be really appreciated.
CSS properties transition and animation allow you to pick the easing
function. Unfortunately, they don’t support all easings and you must
specify the desired easing function yourself (as a Bezier curve).
Easings.net
It would seem that there are 4 default types of easing that should work.
linear
ease
ease-in
ease-out
ease-in-out
These work directly, however the differences are subtle
For more effective types of easing, you have to use a bezier-curve which allows you to create your own easing. For example the below is "easeInOutBack"
cubic-bezier(0.680, -0.550, 0.265, 1.550)
When using with Angular animate function
animate("1500ms 2000ms cubic-bezier(0.680, -0.550, 0.265, 1.550)", style({transform: "translateX(-100%)"}))
You can navigate to this bezier curver generator which should provide you with the ability to create your own easings.
Animate is no longer a part in angular/core.. so you have to import it, its part of the module ngAnimate .. so to use the $animate service you need to import js/lib/angular-animate.js libs.
bower install --save angular-animate
Related
Hello everyone I'm trying to make a complex animation And I'm new to the framer motion so I need help if it's possible.
I'm trying to do this animation
all the animation will be revealed when scrolling but I don't Know How?
I tried this example but I think it will not take me any where example
So, Any clue please?
Thanks in advance.
i think useAnimationControls will help, but i think there is another better solution or another way, but any way i wish this help you here is the documentation, it says that it returns a promise (and also can be used in async function with await).
like the following code:
import { useAnimationControls, motion } from "framer-motion"
export default function App() {
let controls = useAnimationControls()
controls
.start({
opacity: 1,
backgroundColor: "red",
color: "white",
})
.then(() =>
controls.start({
color: "black",
backgroundColor: "lightgreen",
x: -100,
})
)
.then(() => {
controls.start({
opacity: 0,
x: 100,
})
})
return (
<>
<motion.div initial={{ opacity: 0 }} animate={controls}>
hi there
</motion.div>
</>
)
}
the above code will do these things below respectively:
will increase the opacity to 1 and change the color & bg color
then it will change color & bg color again and change the x position
then will decrease the opacity to 0 and x position too
here is another animation library that is simple and also may be useful to use named animejs, and also they have a friend and non-boaring documentation you can check it here
In React-Native, you can use Stylesheet to create css-like stylesheets. The main reason of using styleshee.create in favor of plain js-objects is increased performance. However, you often might want to style components dynamically, often based on their props. I basically found three approaches of doing this:
Note for the following examples: Consider const styles ... to be declared outside of the Component, as it's a common pattern and you might want to share styles between different Components. Consider everything below the tree dots as part of the render function.
Using an array of styles:
const styles = StyleSheet.create({viewStyle: {backgroundColor:'red'}})
...
return <View style={[styles.viewStyle, {color: this.props.color}]} />
Using Stylesheet.flatten:
const styles = StyleSheet.create({viewStyle: {backgroundColor:'red'}})
...
const flattenedStyle = StyleSheet.flatten(styles.viewStyle, {{color: this.props.color}})
return <View style={flattenedStyle} />
Using a function to create the stylesheet:
const styles = (color) => StyleSheet.create({
viewStyle: {
backgroundColor:'red',
color: color
}
})
...
const style = styles(this.props.color).viewStyle
return <View style={style} />
I am wondering which approach is the best regarding to performance, or if there even is another, more performant way? I think Option 2 and 3 are no way to go at all, because dynamically creating new stylesheets on prop-changes undermines the whole purpose of stylesheets. I am happy for any thought or hints on this subject!
Here you can do dynamic styling in react native for each styling.
Like this
<Text style={styles.simpleText('red')}>Required field</Text>
// In styling
const styles = StyleSheet.create({
simpleText: (colorProp = 'black') => ({ // default black set
fontSize: 14,
color: colorProp,
})
})
and you can also pass any data type for conditional styling
One of the approach
// homeSreen
<View style={styles.filterButton(isSelected)}>
<Text> Strawberry </Text>
</View>
// styles.js
import { StyleSheet } from 'react-native';
import { Colors } from '../../theme';
export default StyleSheet.create({
container: {
backgroundColor: Colors.lighter,
},
filterButton: isSelected => ({
padding: 15,
backgroundColor: isSelected? Colors.background.primary: Colors.background.secondary
}),
});
You could memoize stylesheet creation using React hooks, but first you need to do some performance checking in order to determine if stylesheet creation is in fact a CPU and/or memory hog worth optimizing.
Here's an example:
const styles = (color) => StyleSheet.create({
viewStyle: {
backgroundColor:'red',
color: color
}
})
/*
even though makeStyle is defined in EVERY render,
React will only run it ONCE for any given props.color distinct value.
The resulting value `styles` survives re-renders
*/
const makeStyle = () => styles(props.color)
const styles = useMemo(makeStyle, [props.color]);
And here's the official documentation.
Did you consider CSS in JS libraries like Styled components?
You can pass props and get dynamic style regard that:
https://styled-components.com/docs/basics#passed-props
Possibly a bit overkill for simple dynamic styling but Reanimated is very performant and will run the style transition at 60fps https://github.com/software-mansion/react-native-reanimated
It archives this by declaring all the styles needed for an animation/transition ahead of time and runs them on the native thread so there is minimal communication across the JS->Native code bridge.
There is a better explanation on their about page here https://docs.swmansion.com/react-native-reanimated/docs/about
Purpose: I want to add a nice transition effect when click from one page to another
I tried lots of solution online, including:
Angular 2 — Animating Router transitions
Page transition animations with Angular 2.0 router and component interface promises
....
one thing in common is that they all have style like position: absolute or position: fixed added, which breaks my existing app layout.
I remember when I using Angular 1, there's no need to add position: absolute to <div ui-view><div>
Is it possible in Angular 2 or 4?
You can add the absolute positioning exclusively to the leaving animation.
transition(':enter', [
style({transform: 'translateX(100%)'}),
animate('0.3s ease-in-out', style({transform: 'translateX(0%)'}))
]),
transition(':leave', [
style({transform: 'translateX(0%)', position: 'absolute', left: 0, right: 0, top: 0}),
animate('0.3s ease-in-out', style({transform: 'translateX(-100%)'}))
])
So only the leaving route is positioned absolutely, while the entering route is positioned staticly.
If it doesn't work, make sure that your router-outlet is wrapped by position: relative
<div style="position: relative;">
<router-outlet></router-outlet>
</div>
And that your route-components have display: block
#Component({
styles:[':host {display: block;}']
Talking about Angular version 4.3.x. Reading the router documentation, they explain how to add animation between routes. Here is a resume for the lazy ones (including myself).
You want to import animations libraries from #angular/core (and not #angular/animations):
import {
AnimationEntryMetadata,
animate,
state,
style,
trigger
} from '#angular/core';
export const fadeInAnimation: AnimationEntryMetadata = trigger('fadeInAnimation', [
transition(':enter', [
style({
opacity: 0,
transform: 'translateY(20px)'
}),
animate(
'.3s',
style({
opacity: 1,
transform: 'translateY(0)'
})
)
])
]);
Then in your component, use the HostBinding decorator in order to specify the component's layout css properties (you don't need use a fixed or absolute position):
import { Component, OnInit, HostBinding } from '#angular/core';
import { fadeInAnimation } from './../animations/fadein';
#Component({
animations: [fadeInAnimation],
selector: 'app-posts',
templateUrl: './posts.component.html'
})
export class DemandsComponent implements OnInit {
#HostBinding('#fadeInAnimation') fadeInAnimation = true;
#HostBinding('style.display') display = 'block';
#HostBinding('style.position') position = 'relative';
// Rest of the code
}
Adding this to each routed component can be cumbersome. The documentation suggest, and I quote:
Applying route animations to individual components works for a simple demo, but in a real life app, it is better to animate routes based on route paths.
This article from Matias Niemelä can help https://www.yearofmoo.com/2017/06/new-wave-of-animation-features.html#routable-animations
So I am trying to display a transition with ReactCSSTransitionGroup on load of the home page. It is to display a list of items below the jumbotron. This items come from Redux store. They are passed from a container component called home_index.js that is aware of Redux Store. The component itself 'poll-list.js' contains poll-links, the items to be transitioned in; it (and its child) is a DUMB component. Meaning, it has no state nor is it aware of redux store. (Can these components even use ReactCSSTransitionGroup?)
In any case, I cannot, for the life of me, get this fade in transition to work. I know I must be doing something wrong...but cannot figure it out.
const appearTransition = {
transitionName: "fade",
transitionLeave: false,
transitionEnter: false,
transitionAppear: true,
transitionAppearTimeout: 2500
};
let polls;
if (props.pollsList) {
polls = props.pollsList.map((poll, ind) => {
return (
<PollLink
className='poll-link'
title={poll.title}
index={ind}
id={poll.id}
key={ind}
/>
)
});
}
return (
<div className='poll-list'>
<ReactCSSTransitionGroup {...appearTransition}>
{props.pollsList.length > 0 ? polls : null}
</ReactCSSTransitionGroup>
</div>
)
}
And here is the CSS (note I am not doing a Leave, and I have set Appear to true, i just want this to happen on initial load of the home page)
.fade-appear {
opacity: 0.01;
#include prefix(transition, (opacity 2500ms), webkit ms moz o);
}
.fade-appear.fade-appear-active {
opacity: 1;
}
Also, putting ReactCSSTransitionGroup at this level, in this element, makes my flexbox get all weird. The components are no longer in columns of 4 (or however many based on screen width), they are in one single column down the center...
Where do I put the transition group HOC?
Hierarchy:
<HomeIndex>
<Poll-List>
<Poll-Links>
You can simply add this style in your css file, try to remove the hyphen between class name and make it in camelcasing:
.fadeAppear {
opacity: 1;
transition: opacity 0.3s ease-in;-webkit-transition: opacity 0.3s ease-in;
}
import your css file in your redux code,
#import mycss from '../path/style.css'
and add the given class in css in wherever needed.
as:
return (
<div className='poll-list'>
<ReactCSSTransitionGroup className={mycss.fadeAppear} >
{props.pollsList.length > 0 ? polls : null}
</ReactCSSTransitionGroup>
</div>
)
Hope this works!
Angular 1 handles enter, leave and move animations. The Angular 2 documentation describes how to do enter and leave animations (void => * and * => void), but how can one implement move animations in Angular 2?
Read Angular's official guide for animations if you haven't already.
You define animation states and the transitions between them. For instance:
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
inactive and active can be replaced with any arbitrary strings and you can have as many unique states as you wish, but there must be a valid transition to each one or else the animation won't happen. void is a special case for when elements aren't yet attached to the view and * is a wildcard, applying to any of the defined states.
EDIT:
Hmm... well, for one thing, you might be able to use this Sortable library. It claims to support Angular 2 and is pure Javascript (no jQuery) so theoretically, it should work well but I have not used it myself.
Otherwise, I am certain it would be possible purely inside Angular 2, but it would probably require some fairly clever code. Relative motion (irrespective of a component or element's particular position) is easy with transform: translateY() property. The problem is that Angular 2 animation states only apply if the component is in that state so if you give it a translateY(-20px) to move an element up a position, it's not going to keep that position if you want to want to move it up again.
See this plunker for the solution I have come up with.
template: `
<div #thisElement>
<div class="div-box" #moveState="state">Click buttons to move <div>
</div>
<button (click)="moveUp()">Up</button>
<button (click)="moveDown()">Down</button>
`,
I defined animation states for 'moveUp' and 'moveDown' that ONLY apply during the actual animation and a 'static' state that is applied when the component isn't moving.
animations: [
trigger('moveState', [
state('moveUp', style({
transform: 'translateY(-30px)';
})),
state('moveDown', style({
transform: 'translateY(30px)';
})),
state('static', style({
transform: 'translateY(0)';
})),
transition('* => moveUp', animate('100ms ease-in')),
transition('* => moveDown', animate('100ms ease-out')),
transition('* => static', animate('0ms linear'))
])
]
For the function that actually initiates the animation, it applies the 'moveUp' or 'moveDown' state and then starts a timeout that triggers a callback after an amount of time equal to the length of the transition. In the callback, it sets the animation state to 'static' (the transition to the 'static' state is set to 0 ms so we don't actually animate it moving back to a static position). Then we use Renderer to apply a translation for where we want it to ultimately end up (calculated using a position property that would define it's position relative to where it was initially, not it's position in the array). The Renderer applies its styles separately from the animation so we can apply both without them conflicting with each other.
export class MyComponent {
state = 'static';
#ViewChild('thisElement') thisBox: ElementRef;
position: number = 0;
//...
moveUp() {
this.state = 'moveUp';
this.position--;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
moveDown() {
this.state = 'moveDown';
this.position++;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
//...
}
This is only an example of how you can animate moves without having to define states for each possible position it could be in. As far as triggering the animations on array manipulation, you'll have to figure that out for yourself. I would use some kind of implementation with EventEmitters or Subjects to send events to the components that would then decide on whether or not they need to animate or not.