🎯 目标
实现一个带有“吸附感”的滑动容器组件 SwipeSnapView
,适用于:
-
滑动卡片、分页、滚动面板等场景
-
用户滑动后自动吸附到最近的卡片或位置
-
可设置吸附点位置、间距、自定义回弹动画
-
支持横向/纵向布局
-
后续可拓展为分页器、滑动菜单、多列布局吸附等
🧱 动效示意结构
⬅️ 拖动卡片 → 卡片自动对齐吸附 ✅
| [卡片1] [卡片2] [卡片3] |
← 自动吸附对齐卡片边界
🧰 组件实现:SwipeSnapView.ets(横向滑动 + 自动吸附)
@Component
export struct SwipeSnapView {
@Prop items: string[] = []
@Prop itemWidth: number = 120
@Prop gap: number = 12
@Prop onSnap: (index: number) => void = () => {}
@State offset: number = 0
build() {
let startX = 0
let lastX = 0
let totalWidth = this.items.length * (this.itemWidth + this.gap)
Row()
.width('100%')
.height(140)
.clip(true)
.onTouch(event => {
if (event.type === TouchType.Down) {
startX = event.touches[0].x
lastX = this.offset
} else if (event.type === TouchType.Move) {
const delta = event.touches[0].x - startX
this.offset = Math.min(0, Math.max(-(totalWidth - 360), lastX + delta))
} else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
this.snapToClosest()
}
}) {
Row()
.translate({ x: this.offset })
.animateTo({ duration: 300, curve: Curve.EaseOut }) {
this.items.forEach(item => {
Column()
.width(this.itemWidth)
.height(120)
.margin({ right: this.gap })
.backgroundColor('#F1F9FF')
.borderRadius(12)
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center) {
Text(item).fontSize(14).fontColor('#007DFF')
}
})
}
}
}
private snapToClosest() {
const rawIndex = Math.round(-this.offset / (this.itemWidth + this.gap))
const index = Math.max(0, Math.min(this.items.length - 1, rawIndex))
this.offset = -index * (this.itemWidth + this.gap)
this.onSnap(index)
}
}
📦 使用示例
@Entry
@Component
struct DemoSwipeSnap {
@State current: number = 0
build() {
Column({ space: 16 }).padding(20) {
Text(`当前滑动至第 ${this.current + 1} 个卡片`).fontSize(14).fontColor('#333')
SwipeSnapView({
items: ['卡片1', '卡片2', '卡片3', '卡片4', '卡片5'],
onSnap: index => this.current = index
})
}
}
}
✨ 可扩展能力建议
功能 | 说明 |
---|---|
横/纵双向支持 | 设置方向参数支持 vertical 模式 |
吸附位置可自定义 | 允许配置吸附到“左对齐”“中间对齐”等 |
支持分页模式 + 指示器 | 加入分页圆点显示当前页卡片 |
滑动速度/距离智能判断吸附目标 | 快速滑动吸附下一个,慢滑吸附最近 |
📘 下一篇预告
第6篇:【HarmonyOS 5.0.0 或以上】构建弹性回弹容器 ElasticBounceBox:拖动松手回弹 / 支持阻尼 / 过拖吸边动画