In my Nativescript Angular application, I have a TextView within a ScrollView, defined as such:
<ScrollView orientation="vertical" height="70%" width="100%" style="margin-bottom: 1%; background-color:white" (loaded)="onScrollerLoaded($event)">
<TextView
id="terminal" [text]="terminalText" editable="false"
style="color: whitesmoke; background-color: black; font-size: 8%; font-family: monospace" height="100%"
(tap)="onTap($event)" (loaded)="onTerminalLoaded($event)">
</TextView>
</ScrollView>
The purpose of this element is to act as a terminal, and is rapidly printing incoming messages from a bluetooth device.
Currently, the ScrollView is scrolling back to the top whenever I add some text to the terminalText
variable, to which the TextView is bound. I would like to be able to keep the ScrollView at the bottom of the TextView.
A few notes:
I am adding text to the terminalText
variable within my associated component class through this method:
public appendToTerminal(appendStr){
this.terminalText += appendStr;
}
I have tried implementing the following code that would execute once the ScrollView loads:
private scrollIntervalId;
onScrollerLoaded(data: EventData){
if(!this.scrollIntervalId){
this.scrollIntervalId = setInterval(()=>{
this.ngZone.run(() =>
(data.object as any).scrollToVerticalOffset((data.object as any).scrollableHeight, false)
)
}, 10);
}
}
(This attempt is based on an explanation given here
I have only tried this on an Android device, as I do not have access to an Apple device.
you are setting TextView
to fixed height 100% which is will be same as ScrollView
that is why scrollableHeight
will always be 0. you should use minHeight="100%"
.
then you can scroll programmatically to the end when you are appending text to terminal text this.terminalText += appendStr
.
like this
public appendToTerminal(appendStr){
this.terminalText += appendStr;
setTimeout(()=>{
scrollView.scrollToVerticalOffset(scrollView.scrollableHeight, false);
},150);
}
this will append the text then get the scrollableHeight and then will scroll to it.
here is working playground demo:https://play.nativescript.org/?template=play-ng&id=Rs0xnP&v=16
The function below can only be used in the Angular ngDoCheck() or ngAfterContentChecked() lifecycle:
// See https://angular.io/guide/lifecycle-hooks
function goDownScrollView(scrollView: object, animate: boolean = true): boolean {
let neScrollView: ScrollView = <ScrollView>getNativeElement(scrollView),
scrollableHeight: number = neScrollView.scrollableHeight;
console.log("neScrollView:", neScrollView);
console.log("neScrollView scrollableHeight:", scrollableHeight);
if (scrollableHeight > 0) {
neScrollView.scrollToVerticalOffset(scrollableHeight, animate);
return true;
} else {
return false;
}
}
An helper to always get the native element:
function getNativeElement(object: object): object {
return (object.hasOwnProperty("nativeElement")) ? object['nativeElement'] : object;
}
The scrollable height may be zero at the first pass of the lifecycle (for example, if you add elements to your ScrollView with an HTTP request). That's why you have to test the current content with new before scroll:
// See https://angular.io/api/core/ViewChild
@ViewChild("content") private _pageContent: ElementRef<ScrollView>;
public currentContent: object;
private _previousContent: object;
...
ngAfterContentChecked(): void {
if (this.currentContent != this._previousContent) {
let isScrollDown: boolean = goDownScrollView(this._pageContent);
if (isScrollDown) {
this._previousContent = this.currentContent;
}
}
}
来源:https://stackoverflow.com/questions/51181694/nativescript-scroll-to-bottom-of-scrollview-programmatically