HarmonyOS 鸿蒙Next swiper自动循环滑动

发布于 1周前 作者 itying888 来自 鸿蒙OS

HarmonyOS 鸿蒙Next swiper自动循环滑动

问题:onClick事件打印的数据有时候是点击的下一个元素
示例如下:

```typescript
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Page3 {
  swiperController: SwiperController = new SwiperController()
  [@State](/user/State) bannerList: string[]=['123','456','真的家的','怎买了','点击时间','想获取','元素','数字','可是','获取不到','1231','4561','真的家的1','怎买了1','点击时间1','想获取1','元素1','数字1','可是1','获取不到1',]
  [@State](/user/State) autoPlay:boolean = true
  build() {
    Column({ space: 5 }) {
      Swiper(this.swiperController) {
        ForEach(this.bannerList, (item: string, index: number) => {
          Text(item)
            .fontSize(14)
            .textAlign(TextAlign.Center)
            .borderRadius(15)
            .backgroundColor('red')
            .margin({
              top: 0,
              right: 20,
              bottom: 0,
              left: 0
            })
            .onClick(() => {
              console.log('onClickonClick',item)
            })

        },(item: string) => item)
      }
      .disableSwipe(true)
      .width('100%')
      .backgroundColor('#ccc')
      .index(0)
      .autoPlay(this.autoPlay)
      .interval(0)
      .loop(true)
      .duration(3000)
      .indicator(false)
      .displayCount('auto')
      .curve(Curve.Linear)
      .cachedCount(2)
    }.width('50%')
  }
}

更多关于HarmonyOS 鸿蒙Next swiper自动循环滑动的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

17 回复
新年快乐

更多关于HarmonyOS 鸿蒙Next swiper自动循环滑动的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


@Component export struct AA2 { @Prop bannerList: string[] = [] @Prop source: string @Prop line: number @State randomMarginLeft: number[] = [] @State widthArr: number[] = [] @State rowsData: Array<Array<hot_type>> = [] @State remainder: number = 0 @State timer: number | null = 0 @State lastItemOffsetX: number = 0 @State offsetX: number = 0 @State showWidth: number = 0 @State initFlag: boolean = false @State list: Array<hot_type> = [] @State xoffsetList: number[] = [] @State yoffsetList: number[] = [] //@State contentWidthList: number[] = [] @State listFlagY: boolean[] = [] @State listFlagX: boolean[] = [] closeClick(): void = () => { };

aboutToAppear(): void { for (let i = 0; i < this.bannerList.length; i++) { this.list.push(new hot_type(this.bannerList[i], this.getRandomFlag())) } this.dealData() }

init() { this.initFlag = true this.timer = setInterval(() => { for (let i = 0; i < this.xoffsetList.length; i++) { let strJsonx = getInspectorByKey(listItemX${i}) let objx: Record<string, string> = JSON.parse(strJsonx) let rectInfox: string[] = JSON.parse(’[’ + objx.$rect + ‘]’) let rightx: number = JSON.parse(’[’ + rectInfox[1] + ‘]’)[0]

    let strJsony = getInspectorByKey(`listItemY${i}`)
    let objy: Record<string, string> = JSON.parse(strJsony)
    let rectInfoy: string[] = JSON.parse('[' + objy.$rect + ']')
    let righty: number = JSON.parse('[' + rectInfoy[1] + ']')[0]
    if (px2vp(rightx) <= this.showWidth) {
      if (!this.listFlagY[i] && px2vp(righty) <= 0) {
        this.yoffsetList[i] = this.showWidth
        this.listFlagY[i] = true
        this.listFlagX[i] = false
      }
    }

    if (px2vp(righty) <= this.showWidth) {
      if (!this.listFlagX[i] && px2vp(rightx) <= 0) {
        this.xoffsetList[i] = this.showWidth
        this.listFlagX[i] = true
        this.listFlagY[i] = false
      }
    }
    this.yoffsetList[i] -= 0.5
    this.xoffsetList[i] -= 0.5
  }
}, 20)

}

dealData() { // 计算每组的大小 let groupSize = Math.floor(this.list.length / this.line); let remainder = this.list.length % this.line; // 处理剩余的元素 if (remainder > 0) { groupSize += 1; } let startIndex = 0; for (let i = 0; i < this.line; i++) { let endIndex = startIndex + groupSize; this.rowsData.push(this.list.slice(startIndex, endIndex)); startIndex = endIndex; this.randomMarginLeft.push(Math.floor(Math.random() * 80)) this.xoffsetList.push(0) this.listFlagX.push(false) this.listFlagY.push(false) } }

getRandomFlag(): boolean { let numberRandom = parseInt((Math.random() * 101).toString()); return numberRandom % 5 === 0 }

build() { Column() { Row() { Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { Text(‘666’) .fontSize(14) .fontColor(’#000’) Image($r(“app.media.startIcon”)) .width(12) .height(12) .onClick(() => { this.closeClick(); }) } } .padding(10) .height(40) .width(‘100%’)

  List() {
    ForEach(this.rowsData, (item: hot_type[], index) => {
      List() {
        ForEach(item, (child: hot_type) => {
          ListItem() {
            Row() {
              Image($r('app.media.app_icon')).width(11).height(13).margin({ right: 4 })
                .visibility(child.isHot ? Visibility.Visible : Visibility.None)
              Text(child.name)
                .height(30)
                .fontSize(12)
            }
            .onClick(() => {
              console.log('onClick')
            })
            .padding({ left: 8, right: 8 })
          }
          .margin({ right: 8 })
          .backgroundColor('#fff')
          .borderRadius(15)
        })
      }
      .id(`listItemX${index}`)
      .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
        this.yoffsetList.push(Number(newValue.width!))
      })
      .height(30)
      .margin({ top: 8 })
      .animation({
        duration: 1000,
        playMode: PlayMode.Normal,
        tempo: 0.2,
        iterations: -1
      })
      .translate({ x: this.xoffsetList[index], y: 0 })
      .listDirection(Axis.Horizontal)
      .scrollBar(BarState.Off)
    })
  }
  .width('100%')
  .onScrollFrameBegin((offset, state) => {
    return { offsetRemain: 0 }
  })
  .height('calc(100% - 30vp)')
  .listDirection(Axis.Horizontal)
  .scrollBar(BarState.Off)

  List() {
    ForEach(this.rowsData, (item: hot_type[], index) => {
      List() {
        ForEach(item, (child: hot_type) => {
          ListItem() {
            Row() {
              Image($r('app.media.app_icon')).width(11).height(13).margin({ right: 4 })
                .visibility(child.isHot ? Visibility.Visible : Visibility.None)
              Text(child.name)
                .height(30)
                .fontSize(12)
            }
            .onClick(() => {
              console.log('onClick')
            })
            .padding({ left: 8, right: 8 })
          }
          .margin({ right: 8 })
          .backgroundColor('#0f0')
          .borderRadius(15)
        })
      }
      .id(`listItemY${index}`)
      .height(30)
      .margin({ top: 8 })
      .animation({
        duration: 1000,
        playMode: PlayMode.Normal,
        tempo: 0.2,
        iterations: -1
      })
      .translate({
        x: this.yoffsetList[index],
        y: 0
      })
      .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
        // this.contentWidthList.push(Number(newValue.width!))
        // this.maxWidth = Math.max(this.maxWidth, newValue.width as number)
        // this.yoffsetList.push(Number(this.maxWidth))
      })
      .listDirection(Axis.Horizontal)
      .scrollBar(BarState.Off)
    })
  }
  .width('100%')
  .onScrollFrameBegin((offset, state) => {
    return { offsetRemain: 0 }
  })
  .position({
    y: 40
  })
  .height('calc(100% - 30vp)')
  .listDirection(Axis.Horizontal)
  .scrollBar(BarState.Off)
}
.onAreaChange((oldValue: Area, newValue: Area) => {
  this.showWidth = Number(newValue.width)
})
.id('contentItem')
.width('100%')
.backgroundImage($r('app.media.background'))
.backgroundImageSize(ImageSize.FILL)
.height('100%')
.onVisibleAreaChange([0, 1], (isVisible: boolean, currentRatio: number) => {
  if (!isVisible && currentRatio <= 0) {
    this.initFlag = false
    clearInterval(this.timer)
  } else if (isVisible && currentRatio > 0 && !this.initFlag) {
    this.init()
  }
})

} }

class hot_type { name: string isHot: boolean

constructor(name: string, isHot: boolean) { this.name = name; this.isHot = isHot } }

@Component export struct AA { @Prop bannerList: string[] = [] @Prop source: string @Prop line: number @State randomMarginLeft: number[] = [] @State widthArr: number[] = [] @State rowsData: Array<Array<hot_type>> = [] @State remainder: number = 0 @State timer: number | null = 0 @State lastItemOffsetX: number = 0 @State offsetX: number = 0 @State maxWidth: number = 0 @State showWidth: number = 0 @State initFlag: boolean = false @State list: Array<hot_type> = [] @State xoffsetList: number[] = [] @State yoffsetList: number[] = [] @State contentWidthList: number[] = [] closeClick: () => void = () => { };

aboutToAppear(): void { for (let i = 0; i < this.bannerList.length; i++) { this.list.push(new hot_type(this.bannerList[i], this.getRandomFlag())) } this.dealData() }

init() { this.initFlag = true this.timer = setInterval(() => { for (let i = 0; i < this.xoffsetList.length; i++) { if (Math.abs(this.xoffsetList[i]) > 2 * Math.max(this.contentWidthList[i] + this.randomMarginLeft[i] + 100, this.showWidth + this.randomMarginLeft[i] + 100) - 0.5 * this.showWidth) { this.xoffsetList[i] = this.showWidth }

    if (Math.abs(this.yoffsetList[i]) > 2 * Math.max(this.contentWidthList[i] + this.randomMarginLeft[i] + 100,
      this.showWidth + this.randomMarginLeft[i] + 100) - 0.5 * this.showWidth) {
      this.yoffsetList[i] = this.showWidth
    }
    this.xoffsetList[i] -= 0.5
    this.yoffsetList[i] -= 0.5
  }
}, 20)

}

dealData() { // 计算每组的大小 let groupSize = Math.floor(this.list.length / this.line); let remainder = this.list.length % this.line; // 处理剩余的元素 if (remainder > 0) { groupSize += 1; } let startIndex = 0; for (let i = 0; i < this.line; i++) { let endIndex = startIndex + groupSize; this.rowsData.push(this.list.slice(startIndex, endIndex)); startIndex = endIndex; this.randomMarginLeft.push(Math.floor(Math.random() * 80)) console.log(‘this.showWidth’, this.showWidth) this.xoffsetList.push(0) this.yoffsetList.push(0) } }

getRandomFlag(): boolean { let numberRandom = parseInt((Math.random() * 101).toString()); return numberRandom % 5 === 0 }

build() { Column() { Row() { Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { Text(‘666’) .fontSize(14) .fontColor(’#000’) Image(“app.media.startIcon”) .width(12) .height(12) .onClick(() => { this.closeClick(); }) } } .padding(10) .height(40) .width(‘100%’)

  List() {
    ListItem() {
      Column() {
        ForEach(this.rowsData, (item: hot_type[], index) => {
          List() {
            ForEach(item, (child: hot_type) => {
              ListItem() {
                Row() {
                  Image("app.media.app_icon").width(11).height(13).margin({ right: 4 })
                    .visibility(child.isHot ? Visibility.Visible : Visibility.None)
                  Text(child.name)
                    .height(30)
                    .fontSize(12)
                }
                .onClick(() => {
                  console.log('onClick')
                })
                .padding({ left: 8, right: 8 })
              }
              .margin({ right: 8 })
              .backgroundColor('#fff')
              .borderRadius(15)
            })
          }
          .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
            this.contentWidthList.push(Number(newValue.width!))
            this.yoffsetList.push(Number(newValue.width!))
            this.maxWidth = Math.max(this.maxWidth, newValue.width as number)
          })
          .height(30)
          .margin({ top: 8 })
          .animation({
            duration: 1000,
            playMode: PlayMode.Normal,
            tempo: 0.2,
            iterations: -1
          })
          .translate({ x: this.xoffsetList[index], y: 0 })
          .listDirection(Axis.Horizontal)
          .scrollBar(BarState.Off)
        })
      }
    }
  }
  .width('100%')
  .onScrollFrameBegin((offset, state) => {
    return { offsetRemain: 0 }
  })
  .height('calc(100% - 30vp)')
  .listDirection(Axis.Horizontal)
  .scrollBar(BarState.Off)

  List() {
    ListItem() {
      Column() {
        ForEach(this.rowsData, (item: hot_type[], index) => {
          List() {
            ForEach(item, (child: hot_type) => {
              ListItem() {
                Row() {
                  Image("app.media.app_icon").width(11).height(13).margin({ right: 4 })
                    .visibility(child.isHot ? Visibility.Visible : Visibility.None)
                  Text(child.name)
                    .height(30)
                    .fontSize(12)
                }
                .onClick(() => {
                  console.log('onClick')
                })
                .padding({ left: 8, right: 8 })
              }
              .margin({ right: 8 })
              .backgroundColor('#0f0')
              .borderRadius(15)
            })
          }
          .height(30)
          .margin({ top: 8 })
          .animation({
            duration: 1000,
            playMode: PlayMode.Normal,
            tempo: 0.2,
            iterations: -1
          })
          .translate({
            x: this.contentWidthList[index] + this.yoffsetList[index] + 0.5 * this.showWidth,
            y: 0
          })
          .listDirection(Axis.Horizontal)
          .scrollBar(BarState.Off)
        })
      }
    }
  }
  .width('100%')
  .onScrollFrameBegin((offset, state) => {
    return { offsetRemain: 0 }
  })
  .position({
    y: 40
  })
  .height('calc(100% - 30vp)')
  .listDirection(Axis.Horizontal)
  .scrollBar(BarState.Off)
}
.onAreaChange((oldValue: Area, newValue: Area) => {
  this.showWidth = Number(newValue.width)
})
.width('100%')
.backgroundImage("app.media.discovery_bg")
.backgroundImageSize(ImageSize.FILL)
.height('100%')
.onVisibleAreaChange([0, 1], (isVisible: boolean, currentRatio: number) => {
  if (!isVisible && currentRatio <= 0) {
    this.initFlag = false
    clearInterval(this.timer)
  } else if (isVisible && currentRatio > 0 && !this.initFlag) {
    this.init()
  }
})

} }

class hot_type { name: string isHot: boolean

constructor(name: string, isHot: boolean) { this.name = name; this.isHot = isHot } }

问题原因:普通翻页动画是只有图形侧位置变化的属性动画,真实的ui节点在动画过程中不会对应移动

可以试试这种,看看能不能满足你的需求

@Entry
@Component
struct TestPage {
  build() {
    Column() {
      Text() {
        Span("11111").margin({ left: 5 }).backgroundColor('#ff4400')
        Span("22222").margin({ left: 5 }).backgroundColor('#ff4400')
        Span("33333").margin({ left: 5 }).backgroundColor('#ff4400')
        Span("44444").margin({ left: 5 }).backgroundColor('#ff4400')
        Span("55555").margin({ left: 5 }).backgroundColor('#ff4400')
        Span("66666").margin({ left: 5 }).backgroundColor('#ff4400')
      }.width(80).backgroundColor('#c0c0c0').textOverflow({ overflow: TextOverflow.MARQUEE }).maxLines(1)
    }
  }
}

这个就是有问题!怎么试都没用啊,靠

只要这个swiper自动滚动起来,点击其中一个item的中间偏右位置,log就是输出的下一个item

我大概懂了,本身这个swiper组件的意思就是轮播图的作用,你滚动起来的时候,其实这个位置就要显示下一个要展示的卡片了,所以log也就输出了你当前点击卡片的下一个卡片。

swiper设置自动循环之后,组件内部先渲染Text结构,他渲染的每个Text的宽度是一样的,再把文字渲染,Text和文字错位了,导致点击错位,

那为啥不是每一次点击都错位,只有点击text组件偏右侧的时候才出现这种错位的现象,

我在五楼评论了图片,sawiper设置自动循环播放之后Text和文字错位,点击的空白处是Text,

给Text组件设置宽度

试了,不得行,,

播放的时间间隔设为默认值试试,

还有.interval设置成默认值之后点击他就不滚动了,离开之后才慢慢恢复滚动,有遇到这个问题吗?

针对“HarmonyOS 鸿蒙Next swiper自动循环滑动”的问题,以下是一个简洁直接的回答:

在HarmonyOS中,若要实现swiper组件的自动循环滑动,你通常需要利用鸿蒙系统的动画和计时器机制。具体步骤如下:

  1. 配置swiper组件:首先,确保你的swiper组件已经正确配置,包括其包含的item和布局等。

  2. 设置动画效果:为swiper组件设置动画效果,这通常涉及设置滑动的时间、距离等参数。在鸿蒙的XML布局文件中,你可以通过属性来定义这些动画效果。

  3. 使用计时器:为了实现自动循环,你需要使用鸿蒙提供的计时器API(如SystemClock.sleep或更高级的定时器类)。通过定时器,你可以每隔一定时间触发swiper的滑动事件,从而实现自动循环。

  4. 处理边界情况:当swiper滑动到最后一个item时,你需要通过编程方式将其重置到第一个item,以实现循环效果。这通常需要在swiper的滑动事件监听器中进行处理。

请注意,以上步骤是一个大致的框架,具体实现可能需要根据你的应用需求和鸿蒙系统的版本进行调整。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部