feat(basic): 为 RefreshView 添加控制器并优化聊天页面
- 在 basic 中添加 RefreshController 接口,用于控制 RefreshView 的滚动 - 重构 RefreshView 组件,支持通过控制器进行滚动操作- 在 HosChatView 中集成 RefreshController,实现消息自动滚动到最新 - 优化 ChatItemView 的显示逻辑,修复系统消息的显示问题 - 调整 HosChatView 的数据加载和刷新逻辑
这个提交包含在:
父节点
6c17058f61
当前提交
dcb822cc31
@ -1,6 +1,7 @@
|
|||||||
# [v1.0.9] 2025.xx.xx
|
# [v1.0.9] 2025.xx.xx
|
||||||
|
|
||||||
> - `RefreshView`参数不包含`onLoadMore`的时候,上划不应该提示`没有更多数据了`
|
> - `RefreshView`参数不包含`onLoadMore`的时候,上划不应该提示`没有更多数据了`
|
||||||
|
> - `RefreshView`添加一个`controller`,补充跳转到顶部,跳转到底部等方法,具体见文档`4.3`注释
|
||||||
>
|
>
|
||||||
|
|
||||||
# [v1.0.8] 2025.03.11
|
# [v1.0.8] 2025.03.11
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export { WindowHelper } from './src/main/ets/utils/WindowHelper'
|
|||||||
*/
|
*/
|
||||||
export { LoadingView } from './src/main/ets/view/LoadingView'
|
export { LoadingView } from './src/main/ets/view/LoadingView'
|
||||||
export { SafeView } from './src/main/ets/view/SafeView'
|
export { SafeView } from './src/main/ets/view/SafeView'
|
||||||
export { RefreshView } from './src/main/ets/view/RefreshView'
|
export { RefreshView } from './src/main/ets/view/refresh/RefreshView'
|
||||||
/**
|
/**
|
||||||
* 自定义view
|
* 自定义view
|
||||||
*/
|
*/
|
||||||
|
|||||||
22
README.md
22
README.md
@ -466,7 +466,7 @@ build() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.3.[RefreshView](./src/main/ets/view/RefreshView.ets)
|
### 4.3.[RefreshView](src/main/ets/view/refresh/RefreshView.ets)
|
||||||
|
|
||||||
> 下拉刷新,上拉加载更多
|
> 下拉刷新,上拉加载更多
|
||||||
|
|
||||||
@ -487,18 +487,28 @@ build() {
|
|||||||
// ......
|
// ......
|
||||||
RefreshView({
|
RefreshView({
|
||||||
isLoading: this.isLoading,
|
isLoading: this.isLoading,
|
||||||
keyGenerator: (item: Item) => {
|
// 是否自动调用`onRefresh`方法,默认为`true`,加载组件会自动调用一次`onRefresh`
|
||||||
return item.id
|
init: false,
|
||||||
|
// 第一次加载完成,是否定位到底部,默认`false`,定位到顶部
|
||||||
|
positioningToBottom: true,
|
||||||
|
// 控制器,提供跳转到顶部、跳转到底部、是否已经在最底部方法
|
||||||
|
controller: this.msgController,
|
||||||
|
// 唯一标识,view的key
|
||||||
|
keyGenerator: () => {
|
||||||
|
return ToolsHelper.getUuid().toString()
|
||||||
},
|
},
|
||||||
|
// 每页请求的数据大小,根据这个参数判断是否可以上拉加载更多
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
data: this.list ?? [],
|
data: this.list ?? [],
|
||||||
// 这里要用箭头函数,否则buildItem里面的this指向不对
|
// 这里要用箭头函数,否则buildItem里面的this指向不对
|
||||||
customBuilderParam: (item: Item, index: number) => {
|
customBuilderParam: (item: ImMessage, index: number) => {
|
||||||
this.buildItem(item, index)
|
this.buildItem(item, index)
|
||||||
},
|
},
|
||||||
|
// 下拉刷新回调
|
||||||
onRefresh: () => {
|
onRefresh: () => {
|
||||||
this.refresh()
|
this.getHistory()
|
||||||
},
|
},
|
||||||
|
// 上拉加载更多回调
|
||||||
onLoadMore: (pageNum) => {
|
onLoadMore: (pageNum) => {
|
||||||
this.refresh(pageNum)
|
this.refresh(pageNum)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
export interface RefreshController {
|
||||||
|
toTop: (smooth?: boolean) => void
|
||||||
|
toBottom: (smooth?: boolean) => void
|
||||||
|
isAtEnd: () => boolean
|
||||||
|
}
|
||||||
@ -1,24 +1,86 @@
|
|||||||
import { ToolsHelper } from '../utils/ToolsHelper'
|
import { ToolsHelper } from '../../utils/ToolsHelper'
|
||||||
|
import { inspector } from '@kit.ArkUI'
|
||||||
|
import { RefreshController } from './RefreshController'
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export struct RefreshView {
|
export struct RefreshView {
|
||||||
@Link isLoading: boolean
|
@Link isLoading: boolean
|
||||||
@Prop data: Array<ESObject>
|
@Prop @Watch('change') data: Array<ESObject>
|
||||||
@Require keyGenerator?: (item: ESObject, index: number) => string
|
@Require keyGenerator?: (item: ESObject, index: number) => string
|
||||||
|
//是否自动调用`onRefresh`方法,默认为`true`,加载组件会自动调用一次`onRefresh`
|
||||||
init: boolean = true
|
init: boolean = true
|
||||||
|
// 第一次加载完成,是否定位到底部,默认`false`,定位到顶部
|
||||||
|
positioningToBottom: boolean = false
|
||||||
pageSize: number = 10
|
pageSize: number = 10
|
||||||
onLoadMore?: (pageNum: number) => void
|
onLoadMore?: (pageNum: number) => void
|
||||||
onRefresh?: () => void
|
onRefresh?: () => void
|
||||||
|
controller: RefreshController | null = null
|
||||||
private startY: number = 0
|
private startY: number = 0
|
||||||
private endY: number = 0
|
private endY: number = 0
|
||||||
private lastNum: number = 0
|
private lastNum: number = 0
|
||||||
private _openMore: boolean = false
|
private _openMore: boolean = false
|
||||||
private _oTime: number = 0
|
private _oTime: number = 0
|
||||||
|
private _listener: inspector.ComponentObserver = inspector.createComponentObserver('Refresh_View_List');
|
||||||
|
private _scroller: Scroller = new Scroller()
|
||||||
|
private onDrawComplete = () => {
|
||||||
|
this._isLoad = false
|
||||||
|
this.isLoading = false
|
||||||
|
if (!this._firstFinish && this.positioningToBottom) {
|
||||||
|
this._firstFinish = true
|
||||||
|
this.toBottom()
|
||||||
|
} else {
|
||||||
|
if (this._toTop) {
|
||||||
|
this.toTop()
|
||||||
|
this._toTop = false
|
||||||
|
} else if (this._toBottom) {
|
||||||
|
this.toBottom()
|
||||||
|
this._toBottom = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private _firstFinish = false
|
||||||
|
private _isLoad = false
|
||||||
|
private _toTop = false
|
||||||
|
private _toBottom = false
|
||||||
|
|
||||||
|
change() {
|
||||||
|
this._isLoad = true
|
||||||
|
}
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
if (this.init) {
|
if (this.init) {
|
||||||
this.onRefresh && this.onRefresh()
|
this.onRefresh && this.onRefresh()
|
||||||
}
|
}
|
||||||
|
if (this.controller) {
|
||||||
|
this.controller.toTop = (smooth?: boolean) => {
|
||||||
|
this.toTop(smooth)
|
||||||
|
}
|
||||||
|
this.controller.toBottom = (smooth?: boolean) => {
|
||||||
|
this.toBottom(smooth)
|
||||||
|
}
|
||||||
|
this.controller.isAtEnd = () => this._scroller.isAtEnd()
|
||||||
|
}
|
||||||
|
this._listener.on('draw', this.onDrawComplete)
|
||||||
|
}
|
||||||
|
|
||||||
|
toTop(smooth?: boolean) {
|
||||||
|
if (!this._isLoad) {
|
||||||
|
this._scroller.scrollToIndex(0, smooth, ScrollAlign.START)
|
||||||
|
} else {
|
||||||
|
this._toTop = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toBottom(smooth?: boolean) {
|
||||||
|
if (!this._isLoad) {
|
||||||
|
this._scroller.scrollToIndex(this.data.length - 1, smooth, ScrollAlign.END)
|
||||||
|
} else {
|
||||||
|
this._toBottom = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aboutToDisappear(): void {
|
||||||
|
this._listener.off('draw', this.onDrawComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用父组件@Builder装饰的方法初始化子组件@BuilderParam
|
// 使用父组件@Builder装饰的方法初始化子组件@BuilderParam
|
||||||
@ -28,7 +90,9 @@ export struct RefreshView {
|
|||||||
|
|
||||||
Refresh({ refreshing: $$this.isLoading }) {
|
Refresh({ refreshing: $$this.isLoading }) {
|
||||||
if (this.data && this.data.length > 0) {
|
if (this.data && this.data.length > 0) {
|
||||||
List() {
|
List({
|
||||||
|
scroller: this._scroller,
|
||||||
|
}) {
|
||||||
ForEach(this.data ?? [], (item: ESObject, index: number) => {
|
ForEach(this.data ?? [], (item: ESObject, index: number) => {
|
||||||
ListItem() {
|
ListItem() {
|
||||||
this.customBuilderParam(item, index)
|
this.customBuilderParam(item, index)
|
||||||
@ -63,6 +127,7 @@ export struct RefreshView {
|
|||||||
.onScrollIndex((first: number, last: number) => {
|
.onScrollIndex((first: number, last: number) => {
|
||||||
this.lastNum = last + 1
|
this.lastNum = last + 1
|
||||||
})
|
})
|
||||||
|
.id('Refresh_View_List')
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.height('100%')
|
.height('100%')
|
||||||
.alignListItem(ListItemAlign.Center)
|
.alignListItem(ListItemAlign.Center)
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户