Hi,
In my Ionic app,I have a common functionality that relies on the ion-content scroll value to change the size of an image in ion-header. At the top most position, the image will display in its full size. As the user scrolls down, the image will gradually shrink in size.
Here is a simplified template code:
<ion-header>
<ion-img src="logo.png" style="width:{{imgWidth}}px;"></ion-img>
</ion-header>
<ion-content [scrollEvents]="true" (ionScroll)="onScroll($event)">
...other stuff
</ion-content>
In terms of achieving this feature, I don’t have any issues. However I have no idea how to abstract this piece of functionality into a reusable module because as you can tell, it needs to be implemented in multiple pages. Should this be a directive? A component?
Can anyone shed some light?
Thank you in advance.
As customEvent is not working with stackblitz, please test with real project; feel free to let me know if you face any issue in implementation
Directive:
import { Directive ,Input ,Output,EventEmitter } from '@angular/core';
@Directive({
selector : '[appScroll]'
})
export class AppScrollDirective {
@Input() set appScroll(data) {
console.log(data)
/* if(data.detail.scrollTop > 500) {
this.imgWidth.emit(50)
} else {
this.imgWidth.emit(100)
} */
}
@Output() imgWidth = new EventEmitter<any>();
}
Html
<ion-header>
<ion-toolbar>
<ion-title>
My super tabs app
</ion-title>
</ion-toolbar>
<ion-toolbar>
<img src="https://static.thenounproject.com/png/6725-200.png" [style.width.px]="imgWidth">
</ion-toolbar>
</ion-header>
<ion-content [scrollEvents]="true" (ionScroll)="scrollValue = $event" [appScroll]="scrollValue" (imgWidth)="imgWidth = $event">
<div style="margin-top:800px">Scroll me</div>
</ion-content>
ts
export class Tab1Page {
scrollValue;
imgWidth = 100
constructor() {}
}
Playground link: https://stackblitz.com/edit/ionic-v4-angular-tabs-bhztan?file=src%2Fapp%2Ftab1%2Ftab1.page.html
1 Like
@indraraj26 I would like to thank you for steering me into the right direction.
Let me share my final implementation for everyone’s benefit. It still requires repetitive copy-pasting of codes in component TS and HTML files but it’s very minimal so I can live with that.
Custom directive:
import { Directive, Output, EventEmitter, HostListener } from '@angular/core';
@Directive({
selector: '[appVerticalScrollTracker]'
})
export class VerticalScrollTrackerDirective {
@Output() imageWidth: EventEmitter<number> = new EventEmitter();
maxImageWidth: number = 75;
minImageWidth: number = 50;
constructor() { }
@HostListener('ionScroll', ['$event']) onScroll(event: CustomEvent) {
this.calculateSize(event.detail.scrollTop);
}
calculateSize(scrollTop) {
let newSize = this.maxImageWidth - (scrollTop / 20);
if(newSize >= this.minImageWidth) {
this.imageWidth.emit(newSize);
} else {
this.imageWidth.emit(this.minImageWidth);
}
}
}
Component TS file. Just define this single property:
imageWidth: number;
Component template file.
<ion-header>
<ion-img src="logo.png" [style.width.px]="imageWidth"></ion-img>
</ion-header>
<ion-content [scrollEvents]="true" appVerticalScrollTracker (imageWidth)="imageWidth = $event">
...other stuff
</ion-content>
1 Like
Looks good, Can you explain why are you dividing with 20 (scrollTop / 20)
Oh that’s just for gradually altering the width value (px) relative to the scrollTop value. If I just take the raw scrollTop value, the calculated width values would be too great causing the ion-img to change size too rapidly.
1 Like