ListView 仅在上下滚动时刷新
ListView refreshes only on scroll up and down
我写了一个聊天应用程序,但问题是如果另一个用户给我写信,消息不会立即加载。
仅当我向上滚动然后向下滚动时。
如果我写了一条消息,它会立即更新。
我使用 Firebase 和 Nativescript。
TS:
import { DatePipe } from "@angular/common";
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { FormatListNumbered } from "@material-ui/icons";
import { RouterExtensions } from "@nativescript/angular";
import { EventData, ListView, TextField } from "@nativescript/core";
import { ScrollView } from "@nativescript/core/ui/scroll-view"
import { connectableObservableDescriptor } from "rxjs/internal/observable/ConnectableObservable";
import { ChatService, DataChat } from "../shared/chat.service";
import { FormControl } from '@angular/forms';
import { UserService, DataUser } from "../shared/user.service";
import { firestore } from "@nativescript/firebase";
import { AsyncAction } from "rxjs/internal/scheduler/AsyncAction";
import { Screen } from "@nativescript/core"
@Component({
selector: "ItemDetail",
styleUrls: ['item-detail.component.css'],
templateUrl: "./item-detail.component.html",
providers: [DatePipe]
})
export class ItemDetailComponent implements OnInit {
messages: any[] = [];
constructor() { }
ngOnInit(): void {}
loadChat(){
this._chatService.getChat(this.id).then((chat: any) => {
var chatData = chat.data()
chatData["user"].forEach(user => {
if(user != this.me){
this._userService.getUserObject(user).then((userObject:any) => {
this.user = userObject;
});
}
})
try{
chatData["messages"].forEach((msgs:any) => {
this.messages.push(msgs);
})
}catch{
console.log("noch keine nachrichten verfasst");
}
this.unsubscribe = this._chatService.ChatCollection
.doc(chat.id)
.onSnapshot(doc => {
try{
var lastElement = doc.data().messages[doc.data().messages.length-1];
lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
if(this.messages[this.messages.length-1].msg == lastElement.msg){
}else{
this.messages.push(lastElement);
}
}catch{
console.log("noch keine nachrichten verfasst item-detail component")
}
});
this.formatTime();
})
}
sendMessage(){
if(this.text == undefined){
console.log("Sie haben keine Nachricht eingetippt");
}else{
this._chatService.addMessage(this.id, this.text, this.me);
let counter = 0;
setTimeout(() => {
this.messages.forEach(elemt => {
counter ++;
})
this.listView.scrollToIndex(this.counter);
this.clearText();
}, 300)
setTimeout(() => {
this.messages.forEach(elemt => {
counter ++;
})
this.listView.scrollToIndex(this.counter);
this.clearText();
}, 600)
}
}
因此,代码会附加添加到“messages: any[] = [];”的每个新消息。“
HTML:
<ActionBar>
<NavigationButton (tap)="onBackTap()" android.systemIcon="ic_menu_back"></NavigationButton>
<Label [text]="user.name"></Label>
</ActionBar>
<ListView (loaded)="listViewLoaded($event)" class="chat-body" [items]="messages" separatorColor="transparent" style="height: 80%;margin-top: -200px" >
<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>
<StackLayout class="nt-form chat-wrapper" >
<StackLayout loaded="test" id="chat-form" orientation="horizontal" class="nt-input input-field form">
<TextField
#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>
然后 HTML 将其添加到视图中。这适用于我发送的每条消息:
但是如果对方写的是这种情况:
(消息发送:“我是另一个人”)
但是如果我上下滚动它就在那里。
如果我只向下滚动就不会。
此外,如果我在发送来自“另一个人”的消息后立即向下滚动,则会出现此错误:
System.err: An uncaught Exception occurred on "main" thread.
System.err: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]
System.err:
System.err: StackTrace:
System.err: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of
your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]
System.err: at android.widget.ListView.layoutChildren(ListView.java:1717)
System.err: at android.widget.AbsListView$CheckForTap.run(AbsListView.java:3490)
System.err: at android.os.Handler.handleCallback(Handler.java:938)
System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
System.err: at android.os.Looper.loop(Looper.java:223)
System.err: at android.app.ActivityThread.main(ActivityThread.java:7656)
System.err: at java.lang.reflect.Method.invoke(Native Method)
System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
据我了解,这是UI刷新的问题。
ChatService getChat:
getChat(RoomId){
return new Promise((resolve, reject)=>{
this.ChatCollection.doc(RoomId)
.get()
.then(msg => {
resolve(msg);
})
.catch(err=>{
console.log(err);
reject(err);
})
})
}
当值更改来自库时 UI 没有得到更新的问题是因为它运行在 Angular 的区域之外,这说明您必须滚动到触发 UI 更新。
解决这个问题的方法是在调用更新数组的任何地方包装 ngZone
中的 ListView
以确保它的 运行 在 Angular 中的区域。
import { NgZone } from '@angular/core';
constructor(private ngZone: NgZone) {}
this.unsubscribe = this._chatService.ChatCollection
.doc(chat.id)
.onSnapshot(doc => {
// NEW
this.ngZone.run(() => {
try{
var lastElement = doc.data().messages[doc.data().messages.length-1];
lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
if(this.messages[this.messages.length-1].msg == lastElement.msg){
}else{
this.messages.push(lastElement);
}
} catch{
console.log("noch keine nachrichten verfasst item-detail component")
}
});
});
我写了一个聊天应用程序,但问题是如果另一个用户给我写信,消息不会立即加载。
仅当我向上滚动然后向下滚动时。
如果我写了一条消息,它会立即更新。
我使用 Firebase 和 Nativescript。
TS:
import { DatePipe } from "@angular/common";
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { FormatListNumbered } from "@material-ui/icons";
import { RouterExtensions } from "@nativescript/angular";
import { EventData, ListView, TextField } from "@nativescript/core";
import { ScrollView } from "@nativescript/core/ui/scroll-view"
import { connectableObservableDescriptor } from "rxjs/internal/observable/ConnectableObservable";
import { ChatService, DataChat } from "../shared/chat.service";
import { FormControl } from '@angular/forms';
import { UserService, DataUser } from "../shared/user.service";
import { firestore } from "@nativescript/firebase";
import { AsyncAction } from "rxjs/internal/scheduler/AsyncAction";
import { Screen } from "@nativescript/core"
@Component({
selector: "ItemDetail",
styleUrls: ['item-detail.component.css'],
templateUrl: "./item-detail.component.html",
providers: [DatePipe]
})
export class ItemDetailComponent implements OnInit {
messages: any[] = [];
constructor() { }
ngOnInit(): void {}
loadChat(){
this._chatService.getChat(this.id).then((chat: any) => {
var chatData = chat.data()
chatData["user"].forEach(user => {
if(user != this.me){
this._userService.getUserObject(user).then((userObject:any) => {
this.user = userObject;
});
}
})
try{
chatData["messages"].forEach((msgs:any) => {
this.messages.push(msgs);
})
}catch{
console.log("noch keine nachrichten verfasst");
}
this.unsubscribe = this._chatService.ChatCollection
.doc(chat.id)
.onSnapshot(doc => {
try{
var lastElement = doc.data().messages[doc.data().messages.length-1];
lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
if(this.messages[this.messages.length-1].msg == lastElement.msg){
}else{
this.messages.push(lastElement);
}
}catch{
console.log("noch keine nachrichten verfasst item-detail component")
}
});
this.formatTime();
})
}
sendMessage(){
if(this.text == undefined){
console.log("Sie haben keine Nachricht eingetippt");
}else{
this._chatService.addMessage(this.id, this.text, this.me);
let counter = 0;
setTimeout(() => {
this.messages.forEach(elemt => {
counter ++;
})
this.listView.scrollToIndex(this.counter);
this.clearText();
}, 300)
setTimeout(() => {
this.messages.forEach(elemt => {
counter ++;
})
this.listView.scrollToIndex(this.counter);
this.clearText();
}, 600)
}
}
因此,代码会附加添加到“messages: any[] = [];”的每个新消息。“
HTML:
<ActionBar>
<NavigationButton (tap)="onBackTap()" android.systemIcon="ic_menu_back"></NavigationButton>
<Label [text]="user.name"></Label>
</ActionBar>
<ListView (loaded)="listViewLoaded($event)" class="chat-body" [items]="messages" separatorColor="transparent" style="height: 80%;margin-top: -200px" >
<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>
<StackLayout class="nt-form chat-wrapper" >
<StackLayout loaded="test" id="chat-form" orientation="horizontal" class="nt-input input-field form">
<TextField
#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>
然后 HTML 将其添加到视图中。这适用于我发送的每条消息:
但是如果对方写的是这种情况:
(消息发送:“我是另一个人”)
但是如果我上下滚动它就在那里。 如果我只向下滚动就不会。
此外,如果我在发送来自“另一个人”的消息后立即向下滚动,则会出现此错误:
System.err: An uncaught Exception occurred on "main" thread.
System.err: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]
System.err:
System.err: StackTrace:
System.err: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of
your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]
System.err: at android.widget.ListView.layoutChildren(ListView.java:1717)
System.err: at android.widget.AbsListView$CheckForTap.run(AbsListView.java:3490)
System.err: at android.os.Handler.handleCallback(Handler.java:938)
System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
System.err: at android.os.Looper.loop(Looper.java:223)
System.err: at android.app.ActivityThread.main(ActivityThread.java:7656)
System.err: at java.lang.reflect.Method.invoke(Native Method)
System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
据我了解,这是UI刷新的问题。
ChatService getChat:
getChat(RoomId){
return new Promise((resolve, reject)=>{
this.ChatCollection.doc(RoomId)
.get()
.then(msg => {
resolve(msg);
})
.catch(err=>{
console.log(err);
reject(err);
})
})
}
当值更改来自库时 UI 没有得到更新的问题是因为它运行在 Angular 的区域之外,这说明您必须滚动到触发 UI 更新。
解决这个问题的方法是在调用更新数组的任何地方包装 ngZone
中的 ListView
以确保它的 运行 在 Angular 中的区域。
import { NgZone } from '@angular/core';
constructor(private ngZone: NgZone) {}
this.unsubscribe = this._chatService.ChatCollection
.doc(chat.id)
.onSnapshot(doc => {
// NEW
this.ngZone.run(() => {
try{
var lastElement = doc.data().messages[doc.data().messages.length-1];
lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
if(this.messages[this.messages.length-1].msg == lastElement.msg){
}else{
this.messages.push(lastElement);
}
} catch{
console.log("noch keine nachrichten verfasst item-detail component")
}
});
});