We are creating a custom expansion panel and we want to animate a expand_circle_down
material icon such that it rotates 180
degrees over 300
milliseconds when the panel is expanded
or collapsed
.
Approach
Create a new Stackblitz and add @angular/material
as a dependency.
Also within index.html
add the material icons CDN link.
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
Next replace the app.component.ts
implementation with this.
import {
Component,
ChangeDetectionStrategy,
HostListener,
} from '@angular/core';
import {
trigger,
state,
style,
animate,
transition,
} from '@angular/animations';
@Component({
selector: 'my-app',
template: `<mat-icon
[@animationTrigger]="state"
aria-hidden="false"
aria-label="Chevron Animation"
>expand_circle_down</mat-icon>
`,
styleUrls: ['./app.component.css'],
animations: [
trigger('animationTrigger', [
state(
'expanded',
style({
transform: 'rotate(180deg)',
})
),
transition('collapsed => expanded', animate('300ms ease-in')),
transition('expanded => collapsed', animate('300ms ease-out')),
]),
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
public isExpanded = false;
@HostListener('click')
@HostListener('keydown.enter')
@HostListener('keydown.space')
public toggle() {
this.isExpanded = !this.isExpanded;
}
get state(): string {
return this.isExpanded ? 'expanded' : 'collapsed';
}
}
Within the template we have added the icon we wish to animate.
The @animationTrigger
mat-icon
property assignment points to our animation state.
<mat-icon [@animationTrigger]="state" aria-hidden="false" aria-label="Chevron Animation" >expand_circle_down</mat-icon>
The animation state
getter
returns expanded
or collapsed
depending on the value of the isExpanded property.
get state(): string {
return this.isExpanded ? 'expanded' : 'collapsed';
}
The Angular Animation API is used to setup the animations definition within the @Component
declaration.
animations: [
trigger('animationTrigger',
[state('expanded',
style({
transform: 'rotate(180deg)',
})),
transition('collapsed => expanded',
animate('300ms ease-in')),
transition('expanded => collapsed',
animate('300ms ease-out')), ]),
Note that the animation
trigger is what we added to the mat-icon
@animation
property in order to trigger the animation.
[@animationTrigger]="state"
The @HostListener('click')
decoration on the toggle()
method causes the toggle()
to fire whenever the user clicks on the icon, and this updates the state triggering the animation.