HarmonyOS 鸿蒙Next swiper自动循环滑动
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
新年快乐
@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设置自动循环之后,组件内部先渲染Text结构,他渲染的每个Text的宽度是一样的,再把文字渲染,Text和文字错位了,导致点击错位,
那为啥不是每一次点击都错位,只有点击text组件偏右侧的时候才出现这种错位的现象,
我在五楼评论了图片,sawiper设置自动循环播放之后Text和文字错位,点击的空白处是Text,
给Text组件设置宽度
播放的时间间隔设为默认值试试,
还有.interval设置成默认值之后点击他就不滚动了,离开之后才慢慢恢复滚动,有遇到这个问题吗?
针对“HarmonyOS 鸿蒙Next swiper自动循环滑动”的问题,以下是一个简洁直接的回答:
在HarmonyOS中,若要实现swiper组件的自动循环滑动,你通常需要利用鸿蒙系统的动画和计时器机制。具体步骤如下:
-
配置swiper组件:首先,确保你的swiper组件已经正确配置,包括其包含的item和布局等。
-
设置动画效果:为swiper组件设置动画效果,这通常涉及设置滑动的时间、距离等参数。在鸿蒙的XML布局文件中,你可以通过属性来定义这些动画效果。
-
使用计时器:为了实现自动循环,你需要使用鸿蒙提供的计时器API(如
SystemClock.sleep
或更高级的定时器类)。通过定时器,你可以每隔一定时间触发swiper的滑动事件,从而实现自动循环。 -
处理边界情况:当swiper滑动到最后一个item时,你需要通过编程方式将其重置到第一个item,以实现循环效果。这通常需要在swiper的滑动事件监听器中进行处理。
请注意,以上步骤是一个大致的框架,具体实现可能需要根据你的应用需求和鸿蒙系统的版本进行调整。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html