SwiftUI中实现图片绕圆周旋转并保持屏幕垂直朝上
解决SwiftUI图片绕圆周旋转时保持屏幕直立的问题
问题描述
我有三张图片分布在圆周的不同位置,希望它们沿顺时针方向绕圆周旋转,同时全程相对于屏幕保持直立状态。当前代码能实现顺时针旋转,但图片移动时是相对于圆心直立,而非屏幕。试过给旋转角度加负号,结果只是变成逆时针旋转,没解决直立问题。
原代码
import SwiftUI struct AnotherCircleTry: View { @State private var rotationAngle = 0.0 var body: some View { VStack { Spacer() Text("Rotating images!") Spacer() ZStack { Circle() .stroke() .frame(width: 250, height: 250) .hidden() // Image 1 Image("image-1") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle) / 180.0 * .pi) * 100) .rotationEffect(.degrees(rotationAngle), anchor: .center) // Image 2 Image("image-2") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle) / 180.0 * .pi) * 100) .rotationEffect(.degrees((rotationAngle + 120)), anchor: .center) // Image 3 Image("image-3") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle) / 180.0 * .pi) * 100) .rotationEffect(.degrees((rotationAngle + 240)), anchor: .center) } .padding(.horizontal) Spacer() } .onAppear { withAnimation(Animation.linear(duration: 8).repeatForever(autoreverses: false)) { rotationAngle += 360 } } } } #Preview{ AnotherCircleTry() }
解决方案
问题核心在于当前的rotationEffect让图片跟着圆周旋转方向同步转动,导致其相对于圆心直立。要让图片保持屏幕直立,需要给图片反向旋转相同角度,抵消位置变化带来的朝向偏移。
修改后的代码
import SwiftUI struct AnotherCircleTry: View { @State private var rotationAngle = 0.0 var body: some View { VStack { Spacer() Text("Rotating images!") Spacer() ZStack { Circle() .stroke() .frame(width: 250, height: 250) .hidden() // Image 1:反向旋转抵消圆周旋转角度 Image("image-1") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle) / 180.0 * .pi) * 100) .rotationEffect(.degrees(-rotationAngle), anchor: .center) // Image 2:对应初始偏移120度,反向旋转抵消总角度 Image("image-2") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle + 120) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle + 120) / 180.0 * .pi) * 100) .rotationEffect(.degrees(-(rotationAngle + 120)), anchor: .center) // Image 3:对应初始偏移240度,反向旋转抵消总角度 Image("image-3") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) .offset(x: cos(CGFloat(rotationAngle + 240) / 180.0 * .pi) * 100, y: sin(CGFloat(rotationAngle + 240) / 180.0 * .pi) * 100) .rotationEffect(.degrees(-(rotationAngle + 240)), anchor: .center) } .padding(.horizontal) Spacer() } .onAppear { withAnimation(Animation.linear(duration: 8).repeatForever(autoreverses: false)) { rotationAngle += 360 } } } } #Preview{ AnotherCircleTry() }
原理说明
- 图片通过
offset沿圆周移动时,自身朝向会随圆周位置改变而偏移(比如从圆心视角看,图片到上方时会变成横向) - 给图片添加反向的
rotationEffect,刚好抵消这个偏移,让图片始终保持相对于屏幕的直立状态 - 三张图片初始圆周位置相差120度,因此各自的反向旋转角度需要对应加上初始偏移量的负值
内容的提问来源于stack exchange,提问作者dramadom
相关产品推荐
相关产品推荐

