SwiftUI如何根据用户滚动调整视图旋转实现滚轮选择器效果
环形滚轮选择器数字偏转角度联动实现
当前实现效果

目标实现效果

核心要求:数字旋转角度与用户滚动操作实时联动,任意数字滚动到滚轮顶部位置时,保持正向正常显示状态。
现有实现代码
struct myVal : Equatable { let id = UUID() let val : String } enum Direction { case left case right } struct WheelView: View { // 圆环半径 @State var radius : Double = 150 // 滑动方向 @State var direction = Direction.left // 圆环底部位置的数字索引 @State var chosenIndex = 0 // 圆环旋转角度 @Binding var degree : Double let array : [myVal] let circleSize : Double var body: some View { ZStack { let anglePerCount = Double.pi * 2.0 / Double(array.count) let drag = DragGesture() .onEnded { value in if value.startLocation.x > value.location.x + 10 { direction = .left } else if value.startLocation.x < value.location.x - 10 { direction = .right } // 此处调用滚轮移动逻辑 } // MARK: 滚轮容器开始 ZStack { ForEach(0 ..< array.count) { index in let angle = Double(index) * anglePerCount let xOffset = CGFloat(radius * cos(angle)) let yOffset = CGFloat(radius * sin(angle)) Text("\(array[index].val)") .rotationEffect(Angle(degrees: -degree)) .offset(x: xOffset, y: yOffset ) } } .rotationEffect(Angle(degrees: degree)) .gesture(drag) .onAppear() { radius = circleSize/2 - 30 // 30为内边距 } // MARK: 滚轮容器结束 } } }
实现方案
现有逻辑的问题是给所有文本统一加了-degree的反向旋转,只能保证所有文字不跟随圆环整体转动,无法实现「文字随所在位置偏转、到达顶部自动摆正」的效果。
正确实现需要给每个条目单独计算旋转角度,逻辑如下:
- 修正初始角度基准:默认三角函数的0角度对应圆弧3点钟方向,需要先偏移90度,把顶部作为0度基准位置。
- 放弃全局统一反向旋转的逻辑,每个文字的旋转角度取自身当前位置相对于顶部的角度做反向旋转,就能保证:到达顶部的文字刚好正向,两侧文字随位置自然偏转。
- 计算过程统一用弧度做运算,传给SwiftUI旋转方法时再对应转换,避免弧度、角度混算导致的角度错误。
核心代码修改
替换ForEach内部的布局逻辑,同时删除外层滚轮容器的.rotationEffect(Angle(degrees: degree))修饰符(角度已经计算到每个条目属性中,不需要再做整体旋转,避免角度叠加):
ForEach(0 ..< array.count) { index in // 计算单个条目的实时角度:基础角度偏移90度对齐顶部,叠加当前滚轮旋转量 let itemAngle = Double(index) * anglePerCount - Double.pi/2 + (degree * .pi / 180) // 计算条目在圆环上的偏移坐标 let xOffset = CGFloat(radius * cos(itemAngle)) let yOffset = CGFloat(radius * sin(itemAngle)) Text("\(array[index].val)") // 反向旋转条目自身相对于顶部的角度,保证顶部位置文字正向 .rotationEffect(Angle(radians: -itemAngle)) .offset(x: xOffset, y: yOffset) }
可选优化点
- 当前拖拽手势仅在结束时判断方向,没有跟手效果,可以把
degree的更新逻辑移到拖拽的onChanged回调中,根据横向拖拽位移换算角度增量,滚动流畅度会明显提升。 - 滚动结束后可以增加吸附逻辑,自动计算离顶部最近的条目,对齐到整格位置,更符合选择器的交互习惯。
- 如果需要做两侧文字的大小、透明度渐变效果,可以直接根据
itemAngle和顶部0角度的差值做线性映射,不需要额外计算位置。
内容的提问来源于stack exchange,提问作者jooh
相关产品推荐
相关产品推荐

