SwiftUI MagnificationGestureでViewを拡大縮小するサンプルを色々調べた結果行き着いたサンプルコードを書く
SwiftUIのMagnificationGestureで拡大縮小を行い、且つ、拡大縮小の状態を保持して、且つジェスチャーも自然にできるサンプルを探してたけど、全てを満たすコードが無かったのでここに書いておきます。画像はImage構造体を使いますが、URLから取って来る都合で、UIImageも少し拡張しています。
import SwiftUI extension UIImage { public convenience init(url: String) { let url = URL(string: url) do { let data = try Data(contentsOf: url!) self.init(data: data)! return } catch let err { print("Error : \(err.localizedDescription)") } self.init() } } struct MagView: View { @State private var currentAmount: CGFloat = 1 @State private var finalAmount: CGFloat = 1 let image = UIImage(url: "https://picsum.photos/800") func reset() { self.finalAmount = 1 self.currentAmount = 1 } init() { reset() } var body: some View { VStack { Image(uiImage: image) .resizable() .scaleEffect(finalAmount * currentAmount) .frame(width: image.size.width, height: image.size.height) .gesture( MagnificationGesture() .onChanged { amount in self.currentAmount = amount } .onEnded { amount in self.finalAmount *= self.currentAmount self.currentAmount = 1 } ) Text("Current:\(CGFloattoString(currentAmount))").font(.system(size:24)) Text("Final:\(CGFloattoString(finalAmount))").font(.system(size:24)) Text("Scale:\(CGFloattoString(finalAmount * currentAmount))").font(.system(size:24)) Button("Reset", action: reset) } } }
重要な変数はcurrentAmount
とfinalAmount
で、finalAmountは基礎になる倍率値、currentAmountはジェスチャーが有効になっている間の変化率です。ジェスチャーが終了したらfinalAmountに反映し、再度ジェスチャーが行われても拡大縮小のスムーズさを一定に保ちます。