scrollViewの上に置いてあるUIViewをロングプレスで操作するときに詰まった
環境
- xcode
- xcode9
- swift
- swift3
- scrollView
- longpress
- ロングプレス
scrollViewの上に置いてあるUIViewをロングプレスで操作するとき詰まりました。二日間も詰まりました。痛恨の極みです。最近、本当にこういうのはよくないと思いました。遅い。遅すぎる。遅いよりは早い方がいい。15分わからなかったら相談する。これを自分の仕事に対する行動指針にする。
やりたいこと
- スーパービューのscrollViewを追加する。
- scrollViewにUIViewを追加する
- UIViewをロングプレスする
- 現在ロングプレスしてある位置にUIViewの中心を持ってくる
- ロングプレスを動かす度にそれに合わせてUIViewの中心も移動する
うまくいった実行
うまくいった実装
//
// ViewController.swift
// LongPressTutolial
//
// Created by ryosuke-hujisawa on 2017/10/31.
// Copyright © 2017年 ryosuke-hujisawa. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var tapLocation: CGPoint = CGPoint()
let SubView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 250, height: 250))
let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.backgroundColor = UIColor.gray
scrollView.frame = CGRect(x: 0, y: self.view.frame.height/2, width: self.view.frame.width, height: self.view.frame.height/2)
scrollView.contentSize = CGSize(width: 1000, height: 600)
scrollView.bounces = false
scrollView.delegate = self
scrollView.clipsToBounds = false
self.view.addSubview(scrollView)
let bgColor = UIColor.blue
SubView.backgroundColor = bgColor
self.scrollView.addSubview(SubView)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longPressed(_:)))
self.SubView.addGestureRecognizer(longPressRecognizer)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@objc func longPressed(_ sender: UILongPressGestureRecognizer)
{
print("longpressed")
tapLocation = sender.location(in: self.scrollView)
SubView.center = tapLocation
}
}
うまくいかなかった実行
うまくいかなかった実装
//
// ViewController.swift
// ImageRotatedSwift3
//
// Created by ryosuke-hujisawa on 2017/10/30.
// Copyright © 2017年 ryosuke-hujisawa. All rights reserved.
//
import UIKit
var tapLocation: CGPoint = CGPoint()
class ViewController: UIViewController, UIScrollViewDelegate {
let SubView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 250, height: 250))
let scrollView = UIScrollView()
var tapLocation: CGPoint = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressView(sender:)))
longPressGesture.minimumPressDuration = 1
longPressGesture.allowableMovement = 50
self.SubView.addGestureRecognizer(longPressGesture)
scrollView.backgroundColor = UIColor.gray
scrollView.frame = CGRect(x: 0, y: self.view.frame.height/2, width: self.view.frame.width, height: self.view.frame.height/2)
scrollView.contentSize = CGSize(width: 1000, height: 600)
scrollView.bounces = false
scrollView.delegate = self
let bgColor = UIColor.blue
SubView.backgroundColor = bgColor
SubView.isUserInteractionEnabled = true
scrollView.addSubview(SubView)
self.view.addSubview(scrollView)
}
@objc func longPressView(sender: UILongPressGestureRecognizer) {
print("Long Press")
tapLocation = sender.location(in: self.view)
SubView.center = tapLocation
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
なぜ、こんなことになったのか
tapLocation = sender.location(in: self.view)
の部分。現在タップしている位置の基準がスーパービューになっている。SubViewの中心を現在ロングプレスしているロケーションの位置に持ってこようとした場合、ロケーションがスーパービューだとおかしくなる。なぜなら、SubViewはスーパービューではなくscrollViewに追加されているからだ。例えば、scrollViewがViewの上(x100y100)の位置に追加されているとして、scrollの一番左を触ったとしたら、現在ロングプレスしているロケーションの位置は(x0,y0)になる。scrollViewの(x0,y0)の位置に追加されているSubViewの一番はじを触った場合、本当であれば、SubViewは(x-50,y-50)の位置にくるはずだが、実際現在選択されているロケーションの位置は(x100y100)なので、SubViewの中心はscrollViewの中の(x100y100)の位置に移動することになった。正しい実装では、self.SubView.addGestureRecognizer(longPressRecognizer)
のようにSubViewにロングプレスを追加して、そして、sender.location(in: self.scrollView)
のように、現在ロングプレスしている位置をscrollViewを基準にしている。SubViewはscrollViewに追加されているのだから、うまくいく。