如何在watchOS中用SwiftUI实现类系统健身应用的垂直滚动页面
实现类似Apple Watch健身应用的垂直滚动页面
我想要实现一个类似系统健身应用的垂直滚动页面,效果如下:
目前我通过以下代码实现了类似效果:
TabView { page1 .rotationEffect(.degrees(90)) page2 .rotationEffect(.degrees(90)) }.tabViewStyle(.page(indexDisplayMode: .automatic)) .rotationEffect(.degrees(-90))
但该效果不如系统健身应用理想,系统应用支持数码表冠(Digital Crown)操作、动态显示指示器以及自定义颜色。当前实现效果如下:
请问该如何实现符合预期的垂直滚动效果?
解决方案:原生垂直分页ScrollView + 数码表冠绑定
Apple Watch健身应用并未采用旋转TabView的hack方式,而是基于原生垂直分页滚动实现,以下是完整实现方案:
- 构建原生垂直分页滚动
使用ScrollView(.vertical)配合分页行为修饰符,替代旋转TabView的方案,iOS17+/watchOS10+可直接用原生分页API:
ScrollView(.vertical) { VStack(spacing: 0) { page1 .frame(height: WKInterfaceDevice.current().screenBounds.height) page2 .frame(height: WKInterfaceDevice.current().screenBounds.height) // 按需添加更多页面 } } .scrollTargetBehavior(.paging) // 原生分页行为 .scrollIndicators(.hidden) // 隐藏系统滚动条
如果需要兼容旧版本,可替换为.pageSnap()修饰符。
- 绑定数码表冠控制滚动
通过ScrollViewReader结合数码表冠绑定,实现精准的页面切换:
@State private var currentPage = 0 private let pageCount = 2 var body: some View { ScrollViewReader { proxy in VStack(spacing: 0) { ScrollView(.vertical) { VStack(spacing: 0) { page1.id(0) .frame(height: WKInterfaceDevice.current().screenBounds.height) page2.id(1) .frame(height: WKInterfaceDevice.current().screenBounds.height) } .scrollTargetLayout() } .scrollTargetBehavior(.paging) .scrollIndicators(.hidden) // 自定义分页指示器 HStack(spacing: 6) { ForEach(0..<pageCount, id: \.self) { index in Circle() .frame(width: index == currentPage ? 8 : 4, height: index == currentPage ? 8 : 4) .foregroundColor(index == currentPage ? .green : .gray.opacity(0.5)) .animation(.easeInOut, value: currentPage) } } .padding(.bottom, 10) } .focusable() .digitalCrownRotation($currentPage, from: 0, through: pageCount - 1, by: 1, sensitivity: .high) .onChange(of: currentPage) { _, newValue in withAnimation { proxy.scrollTo(newValue, anchor: .top) } } } }
- 关键细节优化
- 每个页面强制设置为屏幕高度,确保分页精准
- 数码表冠的
sensitivity参数设为.high,适配快速切换场景 - 自定义指示器通过
currentPage状态实现动态大小和颜色变化,完全匹配健身应用风格
内容的提问来源于stack exchange,提问作者Haozes
相关产品推荐
相关产品推荐

