I've made a Chat and the function that i'm trying to implement is that the chat should always scroll to the last message.
html:
<ActionBar>
<NavigationButton (tap)="onBackTap()" android.systemIcon="ic_menu_back"></NavigationButton>
<Label [text]="user.name"></Label>
</ActionBar>
<ScrollView #scrollLayout style="height: 80%;margin-top: -200px">
<ListView class="chat-body" [items]="messages" separatorColor="transparent" style="min-height:100%" >
<ng-template let-message="item" let-odd="odd" let-even="even">
<GridLayout rows ="auto, *">
<Label style="padding-right:150px" *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg" textWrap="true"></Label>
<Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" verticalAlignment="bottom" [text]="message.time"></Label>
<Label style="padding-left:170px" *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg" textWrap="true"></Label>
<Label *ngIf="message.sender != me" horizontalAlignment="left" verticalAlignment="bottom" class="chat-timestamp" [text]="message.time"></Label>
</GridLayout>
</ng-template>
</ListView>
</ScrollView>
<StackLayout class="nt-form chat-wrapper" >
<StackLayout loaded="test" id="chat-form" orientation="horizontal" class="nt-input input-field form">
<TextField
(textChange)="onTextChange($event)"
[text]="inputText"
width="800px"
class="-rounded-lg input"
hint="Nachricht"
style="background-color: #ffffff;"
></TextField>
<button width="120px" class="-rounded-lg fa far fas fab" (tap)="sendMessage();" style="margin-left: 15px;" text=""></button>
</StackLayout>
</StackLayout>
ts:
@Component({
selector: "ItemDetail",
styleUrls: ['item-detail.component.css'],
templateUrl: "./item-detail.component.html",
providers: [DatePipe]
})
export class ItemDetailComponent implements OnInit {
@ViewChild('scrollLayout') scrollen: ElementRef;
constructor(){}
ngOnInit(): void {
}
ngAfterViewInit(): void{
setTimeout(()=> {
var scroller = this.scrollen.nativeElement.scrollableHeight
console.log("height", scroller)
this.scrollen.nativeElement.scrollToVerticalOffset(this.scrollen.nativeElement.scrollableHeight, false);
}, 1000);
}
It looks like this:
But should be like this(scrolled down):
The console log in NgAfterViewInit is always "height 0" so it tells me that ListView is 0? How can i get it to scroll down programmaticly?
I think the problem is with the nesting of a ListView
inside a ScrollView
. ListView
already comes with scrolling behavior by default, so you shouldn't need to nest it within a ScrollView
.
<ListView class="chat-body" [items]="messages" separatorColor="transparent" style="min-height:100%">
<ng-template let-message="item" let-odd="odd" let-even="even">
<GridLayout rows ="auto, *">
<Label style="padding-right:150px" *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg" textWrap="true"></Label>
<Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" verticalAlignment="bottom" [text]="message.time"></Label>
<Label style="padding-left:170px" *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg" textWrap="true"></Label>
<Label *ngIf="message.sender != me" horizontalAlignment="left" verticalAlignment="bottom" class="chat-timestamp" [text]="message.time"></Label>
</GridLayout>
</ng-template>
</ListView>
Scrolling to bottom
Instead of ngAfterViewInit
, we can use the ListView
s loaded event to make sure that the listview is loaded and ready to be scrolled.
<ListView (loaded)="listViewLoaded($event)"
class="chat-body" [items]="messages" separatorColor="transparent" style="min-height:100%">
...
</ListView>
listViewLoaded(args: EventData) {
const listView = args.object as ListView;
const lastIndex = this.messages.length - 1;
// you might need a setTimeout here if it still fires too early
listView.scrollToIndex(lastIndex)
// or this if you want the scroll to be animated
listView.scrollToIndexAnimated(lastIndex)
}