iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Mobile Development

從概念發想上架一支SwiftUI app系列 第 4

基礎部分 - 面板部份

  • 分享至 

  • xImage
  •  

今天改善PositionPanel的一項功能,新增一個變數(lastOffset)儲存上一次的位置,下次重新觸發手勢會從這個位置開始移動。也修正Day2的邏輯錯誤,限制移動的邊界應該是正負100之間才對。

struct PositionPanel: View {
    @Binding var offset: CGSize
    @State private var lastOffset: CGSize = .zero

    var body: some View {
        ZStack {
            Rectangle()
                .stroke(Color.green, lineWidth: 2)
                
            MovableCircle()
                .offset(offset)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            let maxOffset = 100.0
                            let newX = max(-maxOffset, min(value.translation.width + lastOffset.width, maxOffset))
                            let newY = max(-maxOffset, min(value.translation.height + lastOffset.height, maxOffset))
                            offset = CGSize(width: newX, height: newY)
                        }
                        .onEnded { _ in
                            lastOffset = offset
                        }
                )
        }
    }
}

第二部分是把旋轉的控制運算實作出來,概念上很像手遊的虛擬搖桿。先採用印出角度的方式,確保是我預期的效果。
-新增一個RotationPanel

struct RotationPanel: View {
    @Binding var rotationOffset: CGSize
    @State private var lastOffset: CGSize = .zero

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Circle()
                    .stroke(Color.gray, lineWidth: 2)
                    .frame(width: 150, height: 150)
                Circle()
                    .fill(Color.blue)
                    .frame(width: 20, height: 20)
                    .offset(rotationOffset)
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                let maxOffset = 75.0
                                let newX = max(-maxOffset, min(value.translation.width + lastOffset.width, maxOffset))
                                let newY = max(-maxOffset, min(value.translation.height + lastOffset.height, maxOffset))
                                rotationOffset = CGSize(width: newX, height: newY)

                            }
                            .onEnded { _ in
                                lastOffset = rotationOffset
                            }
                )
            }
        }
    }
}

-要觀測移動時的角度變化,在PanelView新增一個Text印出數值

Text("角度: (\(atan2(rotationOffset.width, 75) * 360 / .pi, specifier: "%.2f"), \(atan2(-1*rotationOffset.height, 75) * 360 / .pi, specifier: "%.2f"))")

解釋這邊的算法:想像初始角度為手電筒朝上,這時角度為(0, 0)。RotationPanel的藍點移動到最上方,代表手電筒與畫面呈90度平放,朝螢幕上方,依此類推。這裡還有一處要改善,邊界應該要在圓圈內。

畫面如下圖:
Day4畫面

明天的目標是專注在LightZone做出光束的效果,完成後要重構目前的程式碼。
目前有幾個數值都是寫死,遇到不同尺寸裝置會嚴重跑版,也不易維護。


上一篇
基礎部分 - 旋轉面板
下一篇
基礎部分 - 重構討論
系列文
從概念發想上架一支SwiftUI app30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言