カテゴリー
iOS Swift

UIViewをドラッグしRectangleを描く

よくある、指のドラッグに応じて「選択中」の四角いviewを画面に表示する方法。

指のドラッグに応じてシェイプを描く方法はこのSO記事、DashedUIView(UIViewのBorderを破線 dashed にする)についてはこちらのSO記事を参考にしました。

class ViewController: UIViewController {
  
  var initialPoint: CGPoint = .zero
  
  lazy var overlay: CustomDashedView = {
    let view = CustomDashedView()
    view.dashColor = .systemPink
    view.dashWidth = 1
    view.dashLength = 5
    view.betweenDashesSpace = 2
    return view
  }()
  
  override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(overlay)
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(onViewSelected))
    view.addGestureRecognizer(panGesture)
  }
  
  @objc func onViewSelected(_ sender: UIPanGestureRecognizer) {
    let location = sender.location(in: view)
    if sender.state == .began {
      initialPoint = location
    }
    if sender.state == .changed {
    // comparing the initialPoint and the current location, and get the smaller value for the x and y coordinate, set it as the origin of the rect
   // abs() gives the absolute value
    let rect = CGRect(x: min(initialPoint.x, location.x), y: min(initialPoint.y, location.y), width: abs(initialPoint.x - location.x), height: abs(initialPoint.y - location.y))
      print(rect)
      overlay.frame = rect
    }
    if sender.state == .ended {
      overlay.frame.size = .zero
    }
  }
}


class CustomDashedView: UIView {

    var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    var dashWidth: CGFloat = 0
    var dashColor: UIColor = .clear
    var dashLength: CGFloat = 0
    var betweenDashesSpace: CGFloat = 0

    var dashBorder: CAShapeLayer?

    override func layoutSubviews() {
        super.layoutSubviews()
        dashBorder?.removeFromSuperlayer()
        let dashBorder = CAShapeLayer()
        dashBorder.lineWidth = dashWidth
        dashBorder.strokeColor = dashColor.cgColor
        dashBorder.lineDashPattern = [dashLength, betweenDashesSpace] as [NSNumber]
        dashBorder.frame = bounds
        dashBorder.fillColor = nil
        if cornerRadius > 0 {
            dashBorder.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
        } else {
            dashBorder.path = UIBezierPath(rect: bounds).cgPath
        }
        layer.addSublayer(dashBorder)
        self.dashBorder = dashBorder
    }
}