やりたいこと
ピンチやローテートのジェスチャーを複数組み合わせてView(ImageView)の形を変更したい。
ジェスチャーは複数を一度に使えるように。
やり方
UIGestureRecognizerのdelegateを設定し、delegateメソッドで複数のGestureRecognizerの同時使用を許可。
複数のアフィン変換を組み合わせる処理をしてからViewに反映させる。
ジェスチャー(例ではpinchとrotate)使用中のtransformの状態と、終了時のtransformの状態をそれぞれ保存し、ジェスチャー開始時(再開時)は前回の続きから始めるようにする。
つまづいたとこ
Swift3あたりから書き方が変わったせいで、前回のtransformの状態から再開する方法、複数のアフィン変換を組み合わせるコードに迷った。
コード(Swift4)
class ViewController: UIViewController,UIGestureRecognizerDelegate {
var myView = UIImageView()
//ジェスチャーで変化中のtransformを保存
var prevRotate = CGAffineTransform()
var prevScale = CGAffineTransform()
//ジェスチャー終了時のtransformを保存
var prevEndRotate = CGAffineTransform()
var prevEndScale = CGAffineTransform()
override func viewDidLoad() {
super.viewDidLoad()
myView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
myView.image = UIImage(named: "image")
myView.transform = CGAffineTransform.identity //念のため変形を初期化
myView.isUserInteractionEnabled = true //ユーザーインタラクションを許可
myView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY)
self.view.addSubview(myView)
let rotate = UIRotationGestureRecognizer(target: self, action: #selector(ViewController.rotate))
rotate.delegate = self
myView.addGestureRecognizer(rotate)
let pinch = UIPinchGestureRecognizer(target: self, action: #selector(ViewController.pinch))
pinch.delegate = self
myView.addGestureRecognizer(pinch)
//アフィン変換の初期値設定しとかないとダメ
prevRotate = myView.transform
prevScale = myView.transform
prevEndRotate = myView.transform
prevEndScale = myView.transform
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@objc func rotate(sender:UIRotationGestureRecognizer) {
//前回のrotateの続きからrotateする
let nowRotate = prevEndRotate.rotated(by: sender.rotation)
//複数のアフィン変換を組み合わせる
myView.transform = nowRotate.concatenating(prevScale)
prevRotate = nowRotate
//rotate終了時のtransform状態を保存
if sender.state == .ended {
prevEndRotate = nowRotate
}
}
@objc func pinch(sender:UIPinchGestureRecognizer) {
//前回のpinchの続きからscaleを変える
let nowScale = prevEndScale.scaledBy(x: sender.scale, y: sender.scale)
//複数のアフィン変換を組み合わせる
myView.transform = nowScale.concatenating(prevRotate)
prevScale = nowScale
//pinch終了時のtransform状態を保存
if sender.state == UIGestureRecognizerState.ended {
prevEndScale = nowScale
}
}
//複数のrecognizerの同時使用許可
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
0 件のコメント:
コメントを投稿