HarmonyOS鸿蒙Next中如何实现中间放大两边缩小可滑动的轮播Banner效果
HarmonyOS鸿蒙Next中如何实现中间放大两边缩小可滑动的轮播Banner效果 轮播时,中间的放大效果,两边的缩放并且透明度减少。
实现思路:
核心是使用 customContentTransition(transition: SwiperContentAnimatedTransition) 自定义Swiper页面切换动画。在页面跟手滑动和离手后执行切换动画的过程中,会对视窗内所有页面逐帧触发回调, 我们可以在回调中设置透明度、缩放比例、位移等属性来自定义切换动画。
切换过程中,切换到的页面缩放大小和透明度都为1。切出和未切入的根据切换距离计算。
预览效果:

完整demo代码:
/**
* @fileName : SwiperAnimation.ets
* @author : @cxy
* @date : 2025/12/19
* @description : 文件描述
*/
@Component
export struct SwiperAnimation {
@State list: string[] = [
'https://picsum.photos/300/200?random=1',
'https://picsum.photos/300/200?random=2',
'https://picsum.photos/300/200?random=3',
'https://picsum.photos/300/200?random=4',
'https://picsum.photos/300/200?random=5']
@State scaleList: number[] = [1];
@State opacityList: number[] = [1];
private indicatorController: IndicatorComponentController = new IndicatorComponentController();
build() {
Column() {
Swiper() {
ForEach(this.list, (item: string, index: number) => {
Image(item)
.width("calc(100%-120vp)")
.height(200)
.borderRadius(10)
.scale({ x: this.scaleList[index] || 0.87, y: this.scaleList[index] || 0.87 })
.opacity(this.opacityList[index] || 1)
}, (item: string, index: number) => item + index)
}
.prevMargin(45)
.nextMargin(45)
.loop(true)
.autoPlay(true)
.interval(5000)
.indicator(this.indicatorController)
.indicatorInteractive(true)
.width('100%')
.onChange((index) => {
})
.customContentTransition({
// 页面移除视窗时超时1000ms下渲染树
timeout: 1000,
// 对视窗内所有页面逐帧回调transition,在回调中修改opacity、scale、translate、zIndex等属性值,实现自定义动画
transition: (proxy: SwiperContentTransitionProxy) => {
const scale = 0.87
const scaleFactor = 1 - scale * Math.abs(proxy.position); // 最小缩放为 scale
this.scaleList[proxy.index] = Math.max(scaleFactor, scale);
const opacity = 0.5
const opacityFactor = 1 - opacity * Math.abs(proxy.position); // 最小透明度为 opacity
this.opacityList[proxy.index] = Math.max(opacityFactor, opacity);
}
})
IndicatorComponent(this.indicatorController)
.initialIndex(1)
.width('100%')
.style(
new DotIndicator()
.itemWidth(6)
.itemHeight(6)
.selectedItemWidth(15)
.selectedItemHeight(6)
.color('#fff')
.selectedColor('#ff0090ff')
)
.loop(true)
.count(this.list.length)
.onChange((index: number) => {
})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Start)
.width('100%')
.backgroundColor('#aaa')
.padding({
top: 20
})
}
}
更多关于HarmonyOS鸿蒙Next中如何实现中间放大两边缩小可滑动的轮播Banner效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,可通过ArkUI的Swiper组件结合自定义插值器实现该效果。设置Swiper的loop为true开启循环,通过displayMode设置显示模式。关键是在Swiper的item组件上应用scale属性,使用自定义插值器根据滑动位置动态计算缩放比例,中间项为1,两侧按需缩小。同时调整item的zIndex确保层级正确。
在HarmonyOS Next中实现中间放大、两边缩小且可滑动的轮播Banner效果,可以通过ArkUI的Swiper组件结合自定义动画和布局属性来实现。以下是核心实现思路和关键代码示例:
1. 使用Swiper组件作为基础容器
Swiper组件支持水平滑动和分页显示,通过设置loop属性可实现循环轮播。
Swiper() {
// 轮播项内容
}
.loop(true) // 循环播放
.autoPlay(true) // 自动播放
.indicator(false) // 隐藏默认指示器
2. 实现中间放大和两边缩小效果
通过Swiper的onChange事件监听当前页索引,动态计算每个页面的缩放比例和透明度:
- 中间页面:缩放比例为1.0(或更大),透明度为1.0
- 两侧页面:缩放比例减小(如0.85),透明度降低(如0.6)
@State currentIndex: number = 0
Swiper() {
ForEach(this.bannerList, (item: BannerItem, index: number) => {
this.buildBannerItem(item, index)
})
}
.onChange((index: number) => {
this.currentIndex = index
})
3. 自定义轮播项样式
在buildBannerItem方法中,根据当前索引与currentIndex的差值,动态设置每个项的缩放和透明度:
buildBannerItem(item: BannerItem, index: number) {
// 计算当前项与中间项的偏移差
let offset = Math.abs(index - this.currentIndex)
let scale = offset === 0 ? 1.0 : 0.85 // 中间项放大,两侧缩小
let opacity = offset === 0 ? 1.0 : 0.6 // 中间项不透明,两侧半透明
Stack() {
// 轮播内容
Image(item.imageUrl)
.width('100%')
.height(200)
}
.scale({ x: scale, y: scale })
.opacity(opacity)
.animation({ duration: 200, curve: Curve.EaseInOut }) // 添加平滑动画
}
4. 调整布局和间距
通过margin或padding属性调整两侧页面的间距,确保中间项突出显示:
.margin({ left: offset === 1 ? 10 : 0, right: offset === 1 ? 10 : 0 })
5. 优化交互体验
- 添加手势滑动事件,确保滑动流畅
- 结合
PageSlider或自定义指示器增强交互反馈 - 使用
displayPriority优化性能,避免过多页面同时渲染
注意事项
- 确保
Swiper的index与currentIndex同步更新 - 动画曲线建议使用
Curve.EaseInOut保证平滑过渡 - 可结合
@Prop或@Link实现组件间状态同步
此方案通过动态样式和动画实现了视觉差异,同时保持了滑动的流畅性。实际开发中可根据需求调整缩放比例、透明度和动画参数。

