|
@@ -73,12 +73,22 @@ export struct PlaylistDetailPage {
|
|
|
|
|
|
|
|
//长按拖动
|
|
//长按拖动
|
|
|
@State dragItem: number = -1
|
|
@State dragItem: number = -1
|
|
|
|
|
+ @State dragStartIndex: number = -1
|
|
|
|
|
+ @State dragTargetIndex: number = -1
|
|
|
@State scaleItem: number = -1
|
|
@State scaleItem: number = -1
|
|
|
@State neighborItem: number = -1
|
|
@State neighborItem: number = -1
|
|
|
- @State neighborScale: number = -1
|
|
|
|
|
|
|
+ @State neighborScale: number = 1
|
|
|
@State offsetY: number = 0
|
|
@State offsetY: number = 0
|
|
|
- private dragRefOffset: number = 0
|
|
|
|
|
private ITEM_INTV: number = 70
|
|
private ITEM_INTV: number = 70
|
|
|
|
|
+ private AUTO_SCROLL_EDGE: number = 60
|
|
|
|
|
+ private AUTO_SCROLL_STEP: number = 20
|
|
|
|
|
+ private listScroller: ListScroller = new ListScroller()
|
|
|
|
|
+ private listArea?: Area
|
|
|
|
|
+ private dragStartScrollOffset: number = 0
|
|
|
|
|
+ private dragStartTop: number = 0
|
|
|
|
|
+ @State dragOverlayItem: VideoItem | null = null
|
|
|
|
|
+ @State dragOverlayTop: number = 0
|
|
|
|
|
+ private lastDragLogTime: number = 0
|
|
|
//播放列表的拖动List 重新排序
|
|
//播放列表的拖动List 重新排序
|
|
|
@State sonDataSource: LazyDataSource<VideoItem> = new LazyDataSource(this.songList)
|
|
@State sonDataSource: LazyDataSource<VideoItem> = new LazyDataSource(this.songList)
|
|
|
scaleSelect(item: number): number {
|
|
scaleSelect(item: number): number {
|
|
@@ -91,15 +101,81 @@ export struct PlaylistDetailPage {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async itemMove(index: number, newIndex: number): Promise<void> {
|
|
|
|
|
- if (newIndex < 0 || newIndex >= this.songList.length) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ private getDragTranslateY(index: number): number {
|
|
|
|
|
+ if (this.dragItem < 0 || this.dragStartIndex < 0) {
|
|
|
|
|
+ return 0
|
|
|
}
|
|
}
|
|
|
- let tmp = this.songList.splice(index, 1);
|
|
|
|
|
- this.songList.splice(newIndex, 0, tmp[0]);
|
|
|
|
|
- this.sonDataSource.pushArrayData(this.songList)
|
|
|
|
|
- // 3. 更新数据库中的sortOrder
|
|
|
|
|
- await this.updateAllSongsSortOrder()
|
|
|
|
|
|
|
+ if (index === this.dragStartIndex) {
|
|
|
|
|
+ return 0
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.dragTargetIndex < 0 || this.dragTargetIndex === this.dragStartIndex) {
|
|
|
|
|
+ return 0
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.dragTargetIndex > this.dragStartIndex) {
|
|
|
|
|
+ return index > this.dragStartIndex && index <= this.dragTargetIndex ? -this.ITEM_INTV : 0
|
|
|
|
|
+ }
|
|
|
|
|
+ return index >= this.dragTargetIndex && index < this.dragStartIndex ? this.ITEM_INTV : 0
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private updateDragTarget(offsetY: number): void {
|
|
|
|
|
+ if (this.dragStartIndex < 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const rawIndex = this.dragStartIndex + Math.round(offsetY / this.ITEM_INTV)
|
|
|
|
|
+ const clampedIndex = Math.max(0, Math.min(this.songList.length - 1, rawIndex))
|
|
|
|
|
+ this.dragTargetIndex = clampedIndex
|
|
|
|
|
+ if (this.dragTargetIndex !== this.dragStartIndex) {
|
|
|
|
|
+ this.neighborItem = this.dragTargetIndex
|
|
|
|
|
+ this.neighborScale = 0.98
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.neighborItem = -1
|
|
|
|
|
+ this.neighborScale = 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private autoScrollWhileDragging(offsetY: number): void {
|
|
|
|
|
+ if (!this.listArea) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const areaHeight = typeof this.listArea.height === 'number' ? this.listArea.height : Number(this.listArea.height)
|
|
|
|
|
+ if (!Number.isFinite(areaHeight) || areaHeight <= 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const currentOffsetVp = this.listScroller.currentOffset().yOffset
|
|
|
|
|
+ const maxOffsetVp = Math.max(0, this.songList.length * this.ITEM_INTV - areaHeight)
|
|
|
|
|
+ if (maxOffsetVp <= 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const topIndex = Math.floor(currentOffsetVp / this.ITEM_INTV)
|
|
|
|
|
+ const visibleCount = Math.max(1, Math.floor(areaHeight / this.ITEM_INTV))
|
|
|
|
|
+ const bottomIndex = topIndex + visibleCount - 1
|
|
|
|
|
+ let nextOffsetVp = currentOffsetVp
|
|
|
|
|
+
|
|
|
|
|
+ const pointerY = this.dragOverlayTop + this.ITEM_INTV / 2
|
|
|
|
|
+ if (pointerY > areaHeight - this.AUTO_SCROLL_EDGE) {
|
|
|
|
|
+ nextOffsetVp = Math.min(maxOffsetVp, currentOffsetVp + this.AUTO_SCROLL_STEP)
|
|
|
|
|
+ } else if (pointerY < this.AUTO_SCROLL_EDGE) {
|
|
|
|
|
+ nextOffsetVp = Math.max(0, currentOffsetVp - this.AUTO_SCROLL_STEP)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (nextOffsetVp !== currentOffsetVp) {
|
|
|
|
|
+ this.listScroller.scrollTo({ xOffset: 0, yOffset: nextOffsetVp })
|
|
|
|
|
+ LogUtil.info('drag-debug',
|
|
|
|
|
+ `autoScroll offsetY=${offsetY} pointerY=${pointerY} currentOffsetVp=${currentOffsetVp} nextOffsetVp=${nextOffsetVp} topIndex=${topIndex} bottomIndex=${bottomIndex}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private resetDragState(): void {
|
|
|
|
|
+ this.dragItem = -1
|
|
|
|
|
+ this.dragStartIndex = -1
|
|
|
|
|
+ this.dragTargetIndex = -1
|
|
|
|
|
+ this.neighborItem = -1
|
|
|
|
|
+ this.neighborScale = 1
|
|
|
|
|
+ this.offsetY = 0
|
|
|
|
|
+ this.dragStartScrollOffset = 0
|
|
|
|
|
+ this.dragStartTop = 0
|
|
|
|
|
+ this.dragOverlayItem = null
|
|
|
|
|
+ this.dragOverlayTop = 0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
aboutToAppear() {
|
|
aboutToAppear() {
|
|
@@ -570,6 +646,272 @@ export struct PlaylistDetailPage {
|
|
|
.width('100%')
|
|
.width('100%')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private buildSongContent(song: VideoItem, index: number, isOverlay: boolean = false) {
|
|
|
|
|
+ if (isOverlay) {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 歌曲封面 - 改为圆形
|
|
|
|
|
+ Stack({ alignContent: Alignment.TopStart }) {
|
|
|
|
|
+ Image(song.pixelMapPath || $r('app.media.alt'))
|
|
|
|
|
+ .width(48)
|
|
|
|
|
+ .height(48)
|
|
|
|
|
+ .borderRadius(24) // 改为圆形
|
|
|
|
|
+ .objectFit(ImageFit.Cover)
|
|
|
|
|
+ .interpolation(ImageInterpolation.High)
|
|
|
|
|
+ .autoResize(true)
|
|
|
|
|
+ .margin({ left: 20 })
|
|
|
|
|
+ .fillColor(song.pixelMapPath ? undefined : (this.isDarkMode ? Color.White : this.themeColor))
|
|
|
|
|
+ }
|
|
|
|
|
+ .width(64)
|
|
|
|
|
+
|
|
|
|
|
+ // 歌曲信息 - 参考LocalMusic的布局
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 歌曲名称
|
|
|
|
|
+ Text(song.name || song.fileName || '')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Bold : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .margin({ top: 8, left: 12 })
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+
|
|
|
|
|
+ // 歌手和专辑信息 - 参考LocalMusic的第二行布局
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 音质标签
|
|
|
|
|
+ if (song.md5Str) {
|
|
|
|
|
+ Text(song.md5Str?.includes('Lossless') ? '无损' : song.md5Str)
|
|
|
|
|
+ .fontSize(10)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(500)
|
|
|
|
|
+ .padding({ top: 2, right: 6, left: 6, bottom: 2 })
|
|
|
|
|
+ .borderRadius(4)
|
|
|
|
|
+ .backgroundColor('#FFC107')
|
|
|
|
|
+ .visibility(song.md5Str ? Visibility.Visible : Visibility.None)
|
|
|
|
|
+ }
|
|
|
|
|
+ Text(song.artist)
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .margin({ left: 8 })
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
+ Text(song.duration)
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .margin({ left: 8 })
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .margin({ left: 12, top: 4 })
|
|
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .alignItems(HorizontalAlign.Start)
|
|
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
|
|
+
|
|
|
|
|
+ // 排序模式下显示上下移动按钮,否则显示更多按钮
|
|
|
|
|
+ if (this.isSortMode) {
|
|
|
|
|
+ Row({ space: 8 }) {
|
|
|
|
|
+ // 上移按钮
|
|
|
|
|
+ Text('▲')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(index === 0 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
+ .enabled(index > 0)
|
|
|
|
|
+
|
|
|
|
|
+ // 下移按钮
|
|
|
|
|
+ Text('▼')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(index === this.songList.length - 1 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
+ .enabled(index < this.songList.length - 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ .margin({ right: 15 })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Text('⋯')
|
|
|
|
|
+ .fontSize(20)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .opacity(0.6)
|
|
|
|
|
+ .margin({ right: 15 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .height(70)
|
|
|
|
|
+ .justifyContent(FlexAlign.Start)
|
|
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
|
|
+ }
|
|
|
|
|
+ .backgroundColor(Color.Transparent)
|
|
|
|
|
+ .height(70)
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ // 当前播放歌曲的背景高亮
|
|
|
|
|
+ .backgroundColor(this.isPlaying && this.curIndex === index ? themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode) : Color.Transparent)
|
|
|
|
|
+ .border({
|
|
|
|
|
+ width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
|
|
|
+ color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 歌曲封面 - 改为圆形
|
|
|
|
|
+ Stack() {
|
|
|
|
|
+ Image(song.pixelMapPath || $r('app.media.alt'))
|
|
|
|
|
+ .width(48)
|
|
|
|
|
+ .height(48)
|
|
|
|
|
+ .borderRadius(24) // 改为圆形
|
|
|
|
|
+ .objectFit(ImageFit.Cover)
|
|
|
|
|
+ .interpolation(ImageInterpolation.High)
|
|
|
|
|
+ .autoResize(true)
|
|
|
|
|
+ .margin({ left: 20 })
|
|
|
|
|
+ .fillColor(song.pixelMapPath ? undefined : (this.isDarkMode ? Color.White : this.themeColor))
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ this.playSong(song, index)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ .width(64)
|
|
|
|
|
+
|
|
|
|
|
+ // 歌曲信息 - 参考LocalMusic的布局
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 歌曲名称
|
|
|
|
|
+ Text(song.name || song.fileName || '')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Bold : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .margin({ top: 8, left: 12 })
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+
|
|
|
|
|
+ // 歌手和专辑信息 - 参考LocalMusic的第二行布局
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ // 音质标签
|
|
|
|
|
+ if (song.md5Str) {
|
|
|
|
|
+ Text(song.md5Str?.includes('Lossless') ? '无损' : song.md5Str)
|
|
|
|
|
+ .fontSize(10)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(500)
|
|
|
|
|
+ .padding({ top: 2, right: 6, left: 6, bottom: 2 })
|
|
|
|
|
+ .borderRadius(4)
|
|
|
|
|
+ .backgroundColor('#FFC107')
|
|
|
|
|
+ .visibility(song.md5Str ? Visibility.Visible : Visibility.None)
|
|
|
|
|
+ }
|
|
|
|
|
+ Text(song.artist)
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .margin({ left: 8 })
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
+ Text(song.duration)
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .margin({ left: 8 })
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .margin({ left: 12, top: 4 })
|
|
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .alignItems(HorizontalAlign.Start)
|
|
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
|
|
+
|
|
|
|
|
+ // 排序模式下显示上下移动按钮,否则显示更多按钮
|
|
|
|
|
+ if (this.isSortMode) {
|
|
|
|
|
+ Row({ space: 8 }) {
|
|
|
|
|
+ // 上移按钮
|
|
|
|
|
+ Text('▲')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(index === 0 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ if (index > 0) {
|
|
|
|
|
+ this.moveSong(index, index - 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .enabled(index > 0)
|
|
|
|
|
+
|
|
|
|
|
+ // 下移按钮
|
|
|
|
|
+ Text('▼')
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ .fontColor(index === this.songList.length - 1 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ if (index < this.songList.length - 1) {
|
|
|
|
|
+ this.moveSong(index, index + 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .enabled(index < this.songList.length - 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ .margin({ right: 15 })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Text('⋯')
|
|
|
|
|
+ .fontSize(20)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .opacity(0.6)
|
|
|
|
|
+ .margin({ right: 15 })
|
|
|
|
|
+ .bindMenu(this.MoreMenuBuilder(song))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .height(70)
|
|
|
|
|
+ .justifyContent(FlexAlign.Start)
|
|
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
|
|
+ }
|
|
|
|
|
+ .backgroundColor(Color.Transparent)
|
|
|
|
|
+ .height(70)
|
|
|
|
|
+ .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.9 })
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ // 排序模式下禁用点击播放
|
|
|
|
|
+ if (!this.isSortMode) {
|
|
|
|
|
+ this.playSong(song, index)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .stateStyles({
|
|
|
|
|
+ normal: {
|
|
|
|
|
+ .backgroundColor(Color.Transparent)
|
|
|
|
|
+ },
|
|
|
|
|
+ pressed: {
|
|
|
|
|
+ .backgroundColor(this.isSortMode ? Color.Transparent : themeColorWithAlpha(this.themeColor, 0.05, this.isDarkMode))
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ // 当前播放歌曲的背景高亮
|
|
|
|
|
+ .backgroundColor(this.isPlaying && this.curIndex === index ? themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode) : Color.Transparent)
|
|
|
|
|
+ .border({
|
|
|
|
|
+ width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
|
|
|
+ color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor
|
|
|
|
|
+ })
|
|
|
|
|
+ .opacity(this.dragItem === index ? 0.5 : this.pageOpacity)
|
|
|
|
|
+ .translate({ x: 0, y: this.showContent ? 0 : 20 })
|
|
|
|
|
+ .transition(TransitionEffect.OPACITY.animation({
|
|
|
|
|
+ duration: 600,
|
|
|
|
|
+ curve: Curve.EaseOut,
|
|
|
|
|
+ delay: 300 + index * 30
|
|
|
|
|
+ }))
|
|
|
|
|
+ .transition(TransitionEffect.translate({ y: 20 }).animation({
|
|
|
|
|
+ duration: 600,
|
|
|
|
|
+ curve: Curve.EaseOut,
|
|
|
|
|
+ delay: 300 + index * 30
|
|
|
|
|
+ }))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
build() {
|
|
build() {
|
|
|
Column() {
|
|
Column() {
|
|
|
// 顶部安全区和标题栏
|
|
// 顶部安全区和标题栏
|
|
@@ -870,272 +1212,126 @@ export struct PlaylistDetailPage {
|
|
|
|
|
|
|
|
// 歌曲列表 - 参考LocalMusic的MusicItem样式
|
|
// 歌曲列表 - 参考LocalMusic的MusicItem样式
|
|
|
if (this.songList.length > 0) {
|
|
if (this.songList.length > 0) {
|
|
|
- List({ space: 0 }) {
|
|
|
|
|
- LazyForEach(this.sonDataSource, (song: VideoItem, index: number) => {
|
|
|
|
|
- ListItem() {
|
|
|
|
|
- Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
- Row() {
|
|
|
|
|
- // 歌曲封面 - 改为圆形
|
|
|
|
|
- Stack() {
|
|
|
|
|
- Image(song.pixelMapPath || $r('app.media.alt'))
|
|
|
|
|
- .width(48)
|
|
|
|
|
- .height(48)
|
|
|
|
|
- .borderRadius(24) // 改为圆形
|
|
|
|
|
- .objectFit(ImageFit.Cover)
|
|
|
|
|
- .interpolation(ImageInterpolation.High)
|
|
|
|
|
- .autoResize(true)
|
|
|
|
|
- .margin({ left: 20 })
|
|
|
|
|
- .fillColor(song.pixelMapPath ? undefined : (this.isDarkMode ? Color.White : this.themeColor))
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- this.playSong(song, index)
|
|
|
|
|
|
|
+ Stack({ alignContent: Alignment.TopStart }) {
|
|
|
|
|
+ List({ space: 0, scroller: this.listScroller }) {
|
|
|
|
|
+ LazyForEach(this.sonDataSource, (song: VideoItem, index: number) => {
|
|
|
|
|
+ ListItem() {
|
|
|
|
|
+ this.buildSongContent(song, index)
|
|
|
|
|
+ }
|
|
|
|
|
+ //拖动List关键代码开始
|
|
|
|
|
+ .scale({ x: this.scaleSelect(index), y: this.scaleSelect(index) })
|
|
|
|
|
+ .zIndex(this.dragItem === index ? 1 : 0)
|
|
|
|
|
+ .translate({ y: this.getDragTranslateY(index) })
|
|
|
|
|
+ .gesture(
|
|
|
|
|
+ GestureGroup(GestureMode.Sequence,
|
|
|
|
|
+ LongPressGesture({ repeat: true })
|
|
|
|
|
+ .onAction((event?: GestureEvent) => {
|
|
|
|
|
+ this.getUIContext().animateTo({ curve: Curve.Friction, duration: 300 }, () => {
|
|
|
|
|
+ this.scaleItem = index
|
|
|
})
|
|
})
|
|
|
- }
|
|
|
|
|
- .width(64)
|
|
|
|
|
-
|
|
|
|
|
- // 歌曲信息 - 参考LocalMusic的布局
|
|
|
|
|
- Column() {
|
|
|
|
|
- Row() {
|
|
|
|
|
- // 歌曲名称
|
|
|
|
|
- Text(song.name || song.fileName || '')
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
- .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Bold : FontWeight.Normal)
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
- .layoutWeight(1)
|
|
|
|
|
- .margin({ top: 8, left: 12 })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
-
|
|
|
|
|
- // 歌手和专辑信息 - 参考LocalMusic的第二行布局
|
|
|
|
|
- Row() {
|
|
|
|
|
- // 音质标签
|
|
|
|
|
- if (song.md5Str) {
|
|
|
|
|
- Text(song.md5Str?.includes('Lossless') ? '无损' : song.md5Str)
|
|
|
|
|
- .fontSize(10)
|
|
|
|
|
- .fontColor($r('app.color.text_color'))
|
|
|
|
|
- .fontWeight(500)
|
|
|
|
|
- .padding({ top: 2, right: 6, left: 6, bottom: 2 })
|
|
|
|
|
- .borderRadius(4)
|
|
|
|
|
- .backgroundColor( '#FFC107')
|
|
|
|
|
- .visibility(song.md5Str ? Visibility.Visible : Visibility.None)
|
|
|
|
|
- }
|
|
|
|
|
- Text(song.artist)
|
|
|
|
|
- .fontSize(13)
|
|
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ?this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
- .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .margin({ left: 8 })
|
|
|
|
|
- .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
- .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
- Text(song.duration)
|
|
|
|
|
- .fontSize(13)
|
|
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
|
|
- .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .margin({ left: 8 })
|
|
|
|
|
- .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
- .opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .margin({ left: 12, top: 4 })
|
|
|
|
|
- .alignItems(VerticalAlign.Center)
|
|
|
|
|
- }
|
|
|
|
|
- .layoutWeight(1)
|
|
|
|
|
- .alignItems(HorizontalAlign.Start)
|
|
|
|
|
- .justifyContent(FlexAlign.Center)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // 排序模式下显示上下移动按钮,否则显示更多按钮
|
|
|
|
|
- if (this.isSortMode) {
|
|
|
|
|
- Row({ space: 8 }) {
|
|
|
|
|
- // 上移按钮
|
|
|
|
|
- Text('▲')
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(index === 0 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
- (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- if (index > 0) {
|
|
|
|
|
- this.moveSong(index, index - 1)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .enabled(index > 0)
|
|
|
|
|
-
|
|
|
|
|
- // 下移按钮
|
|
|
|
|
- Text('▼')
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(index === this.songList.length - 1 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
- (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- if (index < this.songList.length - 1) {
|
|
|
|
|
- this.moveSong(index, index + 1)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .enabled(index < this.songList.length - 1)
|
|
|
|
|
- }
|
|
|
|
|
- .margin({ right: 15 })
|
|
|
|
|
- } else {
|
|
|
|
|
- Text('⋯')
|
|
|
|
|
- .fontSize(20)
|
|
|
|
|
- .fontColor($r('app.color.text_color'))
|
|
|
|
|
- .opacity(0.6)
|
|
|
|
|
- .margin({ right: 15 })
|
|
|
|
|
- .bindMenu(this.MoreMenuBuilder(song))
|
|
|
|
|
|
|
+ })
|
|
|
|
|
+ .onActionEnd(() => {
|
|
|
|
|
+ this.getUIContext().animateTo({ curve: Curve.Friction, duration: 300 }, () => {
|
|
|
|
|
+ this.scaleItem = -1
|
|
|
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .height(70)
|
|
|
|
|
- .justifyContent(FlexAlign.Start)
|
|
|
|
|
- .alignItems(VerticalAlign.Center)
|
|
|
|
|
- }
|
|
|
|
|
- .backgroundColor(Color.Transparent)
|
|
|
|
|
- .height(70)
|
|
|
|
|
- .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.9 })
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- // 排序模式下禁用点击播放
|
|
|
|
|
- if (!this.isSortMode) {
|
|
|
|
|
- this.playSong(song, index)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ })
|
|
|
|
|
|
|
|
- .stateStyles({
|
|
|
|
|
- normal: {
|
|
|
|
|
- .backgroundColor(Color.Transparent)
|
|
|
|
|
- },
|
|
|
|
|
- pressed: {
|
|
|
|
|
- .backgroundColor(this.isSortMode ? Color.Transparent : themeColorWithAlpha(this.themeColor, 0.05, this.isDarkMode))
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- // 当前播放歌曲的背景高亮
|
|
|
|
|
- .backgroundColor(this.isPlaying && this.curIndex === index ? themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode) : Color.Transparent)
|
|
|
|
|
- .border({
|
|
|
|
|
- width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
|
|
|
- color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor
|
|
|
|
|
- })
|
|
|
|
|
- .opacity(this.pageOpacity)
|
|
|
|
|
- .translate({ x: 0, y: this.showContent ? 0 : 20 })
|
|
|
|
|
- .transition(TransitionEffect.OPACITY.animation({
|
|
|
|
|
- duration: 600,
|
|
|
|
|
- curve: Curve.EaseOut,
|
|
|
|
|
- delay: 300 + index * 30
|
|
|
|
|
- }))
|
|
|
|
|
- .transition(TransitionEffect.translate({ y: 20 }).animation({
|
|
|
|
|
- duration: 600,
|
|
|
|
|
- curve: Curve.EaseOut,
|
|
|
|
|
- delay: 300 + index * 30
|
|
|
|
|
- }))
|
|
|
|
|
- }
|
|
|
|
|
- //拖动List关键代码开始
|
|
|
|
|
- .scale({ x: this.scaleSelect(index), y: this.scaleSelect(index) })
|
|
|
|
|
- .zIndex(this.dragItem === index ? 1 : 0)
|
|
|
|
|
- .translate(this.dragItem === index ? { y: this.offsetY } : { y: 0 })
|
|
|
|
|
- .gesture(
|
|
|
|
|
- GestureGroup(GestureMode.Sequence,
|
|
|
|
|
- LongPressGesture({ repeat: true })
|
|
|
|
|
- .onAction((event?: GestureEvent) => {
|
|
|
|
|
- this.getUIContext().animateTo({ curve: Curve.Friction, duration: 300 }, () => {
|
|
|
|
|
- this.scaleItem = index
|
|
|
|
|
|
|
+ }),
|
|
|
|
|
+ PanGesture({ fingers: 1, direction: null, distance: 0 })
|
|
|
|
|
+ .onActionStart(() => {
|
|
|
|
|
+ const currentOffsetVp = this.listScroller.currentOffset().yOffset
|
|
|
|
|
+ this.dragItem = index
|
|
|
|
|
+ this.dragStartIndex = index
|
|
|
|
|
+ this.dragTargetIndex = index
|
|
|
|
|
+ this.offsetY = 0
|
|
|
|
|
+ this.dragStartScrollOffset = currentOffsetVp
|
|
|
|
|
+ this.dragStartTop = index * this.ITEM_INTV - currentOffsetVp
|
|
|
|
|
+ this.dragOverlayTop = this.dragStartTop
|
|
|
|
|
+ this.dragOverlayItem = song
|
|
|
|
|
+ LogUtil.info('drag-debug',
|
|
|
|
|
+ `start index=${index} currentOffsetVp=${currentOffsetVp} dragStartTop=${this.dragStartTop} listHeight=${this.listArea?.height ?? 'n/a'} listTop=${this.listArea?.position?.y ?? 'n/a'}`)
|
|
|
})
|
|
})
|
|
|
- })
|
|
|
|
|
- .onActionEnd(() => {
|
|
|
|
|
- this.getUIContext().animateTo({ curve: Curve.Friction, duration: 300 }, () => {
|
|
|
|
|
- this.scaleItem = -1
|
|
|
|
|
-
|
|
|
|
|
|
|
+ .onActionUpdate((event: GestureEvent) => {
|
|
|
|
|
+ const currentOffsetVp = this.listScroller.currentOffset().yOffset
|
|
|
|
|
+ const scrollDeltaVp = currentOffsetVp - this.dragStartScrollOffset
|
|
|
|
|
+ const gestureOffset = event.offsetY
|
|
|
|
|
+ const targetOffset = gestureOffset + scrollDeltaVp
|
|
|
|
|
+ this.offsetY = targetOffset
|
|
|
|
|
+ this.dragOverlayTop = this.dragStartTop + gestureOffset
|
|
|
|
|
+ this.updateDragTarget(targetOffset)
|
|
|
|
|
+ this.autoScrollWhileDragging(targetOffset)
|
|
|
|
|
+ if (event.timestamp - this.lastDragLogTime > 100000000) {
|
|
|
|
|
+ this.lastDragLogTime = event.timestamp
|
|
|
|
|
+ LogUtil.info('drag-debug',
|
|
|
|
|
+ `update offsetY=${event.offsetY} gestureOffset=${gestureOffset} currentOffsetVp=${currentOffsetVp} scrollDeltaVp=${scrollDeltaVp} targetOffset=${targetOffset} dragOverlayTop=${this.dragOverlayTop} dragStartIndex=${this.dragStartIndex} dragTargetIndex=${this.dragTargetIndex} listHeight=${this.listArea?.height ?? 'n/a'} listTop=${this.listArea?.position?.y ?? 'n/a'}`)
|
|
|
|
|
+ }
|
|
|
})
|
|
})
|
|
|
-
|
|
|
|
|
- }),
|
|
|
|
|
- PanGesture({ fingers: 1, direction: null, distance: 0 })
|
|
|
|
|
- .onActionStart(() => {
|
|
|
|
|
- this.dragItem = index // 记录当前拖动项索引
|
|
|
|
|
- this.dragRefOffset = 0 // 重置偏移基准
|
|
|
|
|
- })
|
|
|
|
|
- .onActionUpdate((event: GestureEvent) => {
|
|
|
|
|
- this.offsetY = event.offsetY - this.dragRefOffset;
|
|
|
|
|
- this.neighborItem = -1;
|
|
|
|
|
- let indexA = this.songList.indexOf(song);
|
|
|
|
|
- // LogUtil.info('onecold indexA = '+indexA +' index=='+index)
|
|
|
|
|
- let curveValue: curves.ICurve = curves.initCurve(Curve.Sharp);
|
|
|
|
|
- let value: number = 0;
|
|
|
|
|
-
|
|
|
|
|
- if (this.offsetY < 0) {
|
|
|
|
|
- value = curveValue.interpolate(-this.offsetY / this.ITEM_INTV);
|
|
|
|
|
- this.neighborItem = indexA - 1;
|
|
|
|
|
- this.neighborScale = 1 - value / 20;
|
|
|
|
|
- } else if (this.offsetY > 0) {
|
|
|
|
|
- value = curveValue.interpolate(this.offsetY / this.ITEM_INTV);
|
|
|
|
|
- this.neighborItem = indexA + 1;
|
|
|
|
|
- this.neighborScale = 1 - value / 20;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- if (this.offsetY > this.ITEM_INTV / 2 && indexA + 1 < this.songList.length) {
|
|
|
|
|
- this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
|
|
|
- this.offsetY -= this.ITEM_INTV;
|
|
|
|
|
- this.dragRefOffset += this.ITEM_INTV;
|
|
|
|
|
- this.itemMove(indexA, indexA + 1);
|
|
|
|
|
- });
|
|
|
|
|
- } else if (this.offsetY < -this.ITEM_INTV / 2 && indexA - 1 >= 0) {
|
|
|
|
|
|
|
+ .onActionEnd((event: GestureEvent) => {
|
|
|
|
|
+ const fromIndex = this.dragStartIndex
|
|
|
|
|
+ const toIndex = this.dragTargetIndex
|
|
|
this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
|
- this.offsetY += this.ITEM_INTV;
|
|
|
|
|
- this.dragRefOffset -= this.ITEM_INTV;
|
|
|
|
|
- this.itemMove(indexA, indexA - 1);
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ this.resetDragState()
|
|
|
|
|
+ })
|
|
|
|
|
+ this.getUIContext().animateTo({
|
|
|
|
|
+ curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
|
|
|
|
|
+ }, () => {
|
|
|
|
|
+ this.scaleItem = -1
|
|
|
|
|
+ })
|
|
|
|
|
+ if (fromIndex >= 0 && toIndex >= 0 && fromIndex !== toIndex) {
|
|
|
|
|
+ void this.moveSong(fromIndex, toIndex)
|
|
|
|
|
+ }
|
|
|
|
|
+ this.isSortMode = true
|
|
|
|
|
|
|
|
- })
|
|
|
|
|
- .onActionEnd((event: GestureEvent) => {
|
|
|
|
|
|
|
+ })
|
|
|
|
|
|
|
|
|
|
+ )
|
|
|
|
|
+ .onCancel(() => {
|
|
|
this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
|
- this.dragItem = -1
|
|
|
|
|
- this.neighborItem = -1
|
|
|
|
|
|
|
+ this.resetDragState()
|
|
|
})
|
|
})
|
|
|
this.getUIContext().animateTo({
|
|
this.getUIContext().animateTo({
|
|
|
curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
|
|
curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
|
|
|
}, () => {
|
|
}, () => {
|
|
|
this.scaleItem = -1
|
|
this.scaleItem = -1
|
|
|
})
|
|
})
|
|
|
- this.isSortMode = true
|
|
|
|
|
|
|
|
|
|
})
|
|
})
|
|
|
|
|
+ ) //拖动List关键代码结束
|
|
|
|
|
|
|
|
- )
|
|
|
|
|
- .onCancel(() => {
|
|
|
|
|
- this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
|
|
|
|
|
- this.dragItem = -1
|
|
|
|
|
- this.neighborItem = -1
|
|
|
|
|
- })
|
|
|
|
|
- this.getUIContext().animateTo({
|
|
|
|
|
- curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
|
|
|
|
|
- }, () => {
|
|
|
|
|
- this.scaleItem = -1
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- ) //拖动List关键代码结束
|
|
|
|
|
|
|
+ }, (item: VideoItem) => item.filePath)
|
|
|
|
|
+ }
|
|
|
|
|
+ .onAreaChange((oldValue: Area, newValue: Area) => {
|
|
|
|
|
+ this.listArea = newValue
|
|
|
|
|
+ })
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .reuseId('list_item')
|
|
|
|
|
+ .backgroundColor($r('app.color.bg_card'))
|
|
|
|
|
+ .borderRadius(12)
|
|
|
|
|
+ .divider({
|
|
|
|
|
+ strokeWidth: 0.5,
|
|
|
|
|
+ color: '#0000001a',
|
|
|
|
|
+ startMargin: 80,
|
|
|
|
|
+ endMargin: 20
|
|
|
|
|
+ })
|
|
|
|
|
+ .opacity(this.pageOpacity)
|
|
|
|
|
+ .zIndex(0)
|
|
|
|
|
+ .scale({ x: this.contentScale, y: this.contentScale })
|
|
|
|
|
+ .transition(TransitionEffect.OPACITY.animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
|
|
|
|
|
+ .transition(TransitionEffect.scale({ x: 0.95, y: 0.95 }).animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
|
|
|
|
|
|
|
|
- }, (item: VideoItem) => item.filePath)
|
|
|
|
|
|
|
+ if (this.dragOverlayItem) {
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ this.buildSongContent(this.dragOverlayItem, this.dragStartIndex, true)
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .position({ x: 0, y: this.dragOverlayTop })
|
|
|
|
|
+ .zIndex(100)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ .clip(false)
|
|
|
.width('100%')
|
|
.width('100%')
|
|
|
.layoutWeight(1)
|
|
.layoutWeight(1)
|
|
|
- .reuseId('list_item')
|
|
|
|
|
- .backgroundColor($r('app.color.bg_card'))
|
|
|
|
|
.margin({ left: 16, right: 16 })
|
|
.margin({ left: 16, right: 16 })
|
|
|
- .borderRadius(12)
|
|
|
|
|
- .divider({
|
|
|
|
|
- strokeWidth: 0.5,
|
|
|
|
|
- color: '#0000001a',
|
|
|
|
|
- startMargin: 80,
|
|
|
|
|
- endMargin: 20
|
|
|
|
|
- })
|
|
|
|
|
- .opacity(this.pageOpacity)
|
|
|
|
|
- .scale({ x: this.contentScale, y: this.contentScale })
|
|
|
|
|
- .transition(TransitionEffect.OPACITY.animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
|
|
|
|
|
- .transition(TransitionEffect.scale({ x: 0.95, y: 0.95 }).animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
|
|
|
|
|
} else {
|
|
} else {
|
|
|
// 空状态
|
|
// 空状态
|
|
|
Column() {
|
|
Column() {
|