123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- //
- // CropRectView.swift
- // CropViewController
- //
- // Created by Guilherme Moura on 2/26/16.
- // Copyright © 2016 Reefactor, Inc. All rights reserved.
- // Credit https://github.com/sprint84/PhotoCropEditor
- import UIKit
- protocol CropRectViewDelegate: class {
- func cropRectViewDidBeginEditing(_ view: CropRectView)
- func cropRectViewDidChange(_ view: CropRectView)
- func cropRectViewDidEndEditing(_ view: CropRectView)
- }
- class CropRectView: UIView, ResizeControlDelegate {
- weak var delegate: CropRectViewDelegate?
- var showsGridMajor = true {
- didSet {
- setNeedsDisplay()
- }
- }
- var showsGridMinor = false {
- didSet {
- setNeedsDisplay()
- }
- }
- var keepAspectRatio = false {
- didSet {
- if keepAspectRatio {
- let width = bounds.width
- let height = bounds.height
- fixedAspectRatio = min(width / height, height / width)
- }
- }
- }
-
- fileprivate var resizeImageView: UIImageView!
- fileprivate let topLeftCornerView = ResizeControl()
- fileprivate let topRightCornerView = ResizeControl()
- fileprivate let bottomLeftCornerView = ResizeControl()
- fileprivate let bottomRightCornerView = ResizeControl()
- fileprivate let topEdgeView = ResizeControl()
- fileprivate let leftEdgeView = ResizeControl()
- fileprivate let rightEdgeView = ResizeControl()
- fileprivate let bottomEdgeView = ResizeControl()
- fileprivate var initialRect = CGRect.zero
- fileprivate var fixedAspectRatio: CGFloat = 0.0
-
- override init(frame: CGRect) {
- super.init(frame: frame)
- initialize()
- }
-
- required init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
- initialize()
- }
-
- fileprivate func initialize() {
- backgroundColor = UIColor.clear
- contentMode = .redraw
-
- resizeImageView = UIImageView(frame: bounds.insetBy(dx: -2.0, dy: -2.0))
- resizeImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- let bundle = Bundle(for: type(of: self))
- let image = UIImage(named: "PhotoCropEditorBorder", in: bundle, compatibleWith: nil)
- resizeImageView.image = image?.resizableImage(withCapInsets: UIEdgeInsets(top: 23.0, left: 23.0, bottom: 23.0, right: 23.0))
- addSubview(resizeImageView)
-
- topEdgeView.delegate = self
- addSubview(topEdgeView)
- leftEdgeView.delegate = self
- addSubview(leftEdgeView)
- rightEdgeView.delegate = self
- addSubview(rightEdgeView)
- bottomEdgeView.delegate = self
- addSubview(bottomEdgeView)
-
- topLeftCornerView.delegate = self
- addSubview(topLeftCornerView)
- topRightCornerView.delegate = self
- addSubview(topRightCornerView)
- bottomLeftCornerView.delegate = self
- addSubview(bottomLeftCornerView)
- bottomRightCornerView.delegate = self
- addSubview(bottomRightCornerView)
- }
-
- override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
- for subview in subviews where subview is ResizeControl {
- if subview.frame.contains(point) {
- return subview
- }
- }
- return nil
- }
-
- override func draw(_ rect: CGRect) {
- super.draw(rect)
-
- let width = bounds.width
- let height = bounds.height
-
- for i in 0 ..< 3 {
- let borderPadding: CGFloat = 0.5
-
- if showsGridMinor {
- for j in 1 ..< 3 {
- UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 0.3).set()
- UIRectFill(CGRect(x: round((width / 9.0) * CGFloat(j) + (width / 3.0) * CGFloat(i)), y: borderPadding, width: 1.0, height: round(height) - borderPadding * 2.0))
- UIRectFill(CGRect(x: borderPadding, y: round((height / 9.0) * CGFloat(j) + (height / 3.0) * CGFloat(i)), width: round(width) - borderPadding * 2.0, height: 1.0))
- }
- }
-
- if showsGridMajor {
- if i > 0 {
- UIColor.white.set()
- UIRectFill(CGRect(x: round(CGFloat(i) * width / 3.0), y: borderPadding, width: 1.0, height: round(height) - borderPadding * 2.0))
- UIRectFill(CGRect(x: borderPadding, y: round(CGFloat(i) * height / 3.0), width: round(width) - borderPadding * 2.0, height: 1.0))
- }
- }
- }
- }
-
- override func layoutSubviews() {
- super.layoutSubviews()
-
- topLeftCornerView.frame.origin = CGPoint(x: topLeftCornerView.bounds.width / -2.0, y: topLeftCornerView.bounds.height / -2.0)
- topRightCornerView.frame.origin = CGPoint(x: bounds.width - topRightCornerView.bounds.width - 2.0, y: topRightCornerView.bounds.height / -2.0)
- bottomLeftCornerView.frame.origin = CGPoint(x: bottomLeftCornerView.bounds.width / -2.0, y: bounds.height - bottomLeftCornerView.bounds.height / 2.0)
- bottomRightCornerView.frame.origin = CGPoint(x: bounds.width - bottomRightCornerView.bounds.width / 2.0, y: bounds.height - bottomRightCornerView.bounds.height / 2.0)
-
- topEdgeView.frame = CGRect(x: topLeftCornerView.frame.maxX, y: topEdgeView.frame.height / -2.0, width: topRightCornerView.frame.minX - topLeftCornerView.frame.maxX, height: topEdgeView.bounds.height)
- leftEdgeView.frame = CGRect(x: leftEdgeView.frame.width / -2.0, y: topLeftCornerView.frame.maxY, width: leftEdgeView.frame.width, height: bottomLeftCornerView.frame.minY - topLeftCornerView.frame.maxY)
- bottomEdgeView.frame = CGRect(x: bottomLeftCornerView.frame.maxX, y: bottomLeftCornerView.frame.minY, width: bottomRightCornerView.frame.minX - bottomLeftCornerView.frame.maxX, height: bottomEdgeView.frame.height)
- rightEdgeView.frame = CGRect(x: bounds.width - rightEdgeView.frame.width / 2.0, y: topRightCornerView.frame.maxY, width: rightEdgeView.frame.width, height: bottomRightCornerView.frame.minY - topRightCornerView.frame.maxY)
- }
-
- func enableResizing(_ enabled: Bool) {
- resizeImageView.isHidden = !enabled
-
- topLeftCornerView.enabled = enabled
- topRightCornerView.enabled = enabled
- bottomLeftCornerView.enabled = enabled
- bottomRightCornerView.enabled = enabled
-
- topEdgeView.enabled = enabled
- leftEdgeView.enabled = enabled
- bottomEdgeView.enabled = enabled
- rightEdgeView.enabled = enabled
- }
- // MARK: - ResizeControl delegate methods
- func resizeControlDidBeginResizing(_ control: ResizeControl) {
- initialRect = frame
- delegate?.cropRectViewDidBeginEditing(self)
- }
-
- func resizeControlDidResize(_ control: ResizeControl) {
- frame = cropRectWithResizeControlView(control)
- delegate?.cropRectViewDidChange(self)
- }
-
- func resizeControlDidEndResizing(_ control: ResizeControl) {
- delegate?.cropRectViewDidEndEditing(self)
- }
-
- fileprivate func cropRectWithResizeControlView(_ resizeControl: ResizeControl) -> CGRect {
- var rect = frame
-
- if resizeControl == topEdgeView {
- rect = CGRect(x: initialRect.minX,
- y: initialRect.minY + resizeControl.translation.y,
- width: initialRect.width,
- height: initialRect.height - resizeControl.translation.y)
-
- if keepAspectRatio {
- rect = constrainedRectWithRectBasisOfHeight(rect)
- }
- } else if resizeControl == leftEdgeView {
- rect = CGRect(x: initialRect.minX + resizeControl.translation.x,
- y: initialRect.minY,
- width: initialRect.width - resizeControl.translation.x,
- height: initialRect.height)
-
- if keepAspectRatio {
- rect = constrainedRectWithRectBasisOfWidth(rect)
- }
- } else if resizeControl == bottomEdgeView {
- rect = CGRect(x: initialRect.minX,
- y: initialRect.minY,
- width: initialRect.width,
- height: initialRect.height + resizeControl.translation.y)
-
- if keepAspectRatio {
- rect = constrainedRectWithRectBasisOfHeight(rect)
- }
- } else if resizeControl == rightEdgeView {
- rect = CGRect(x: initialRect.minX,
- y: initialRect.minY,
- width: initialRect.width + resizeControl.translation.x,
- height: initialRect.height)
-
- if keepAspectRatio {
- rect = constrainedRectWithRectBasisOfWidth(rect)
- }
- } else if resizeControl == topLeftCornerView {
- rect = CGRect(x: initialRect.minX + resizeControl.translation.x,
- y: initialRect.minY + resizeControl.translation.y,
- width: initialRect.width - resizeControl.translation.x,
- height: initialRect.height - resizeControl.translation.y)
-
- if keepAspectRatio {
- var constrainedFrame: CGRect
- if abs(resizeControl.translation.x) < abs(resizeControl.translation.y) {
- constrainedFrame = constrainedRectWithRectBasisOfHeight(rect)
- } else {
- constrainedFrame = constrainedRectWithRectBasisOfWidth(rect)
- }
- constrainedFrame.origin.x -= constrainedFrame.width - rect.width
- constrainedFrame.origin.y -= constrainedFrame.height - rect.height
- rect = constrainedFrame
- }
- } else if resizeControl == topRightCornerView {
- rect = CGRect(x: initialRect.minX,
- y: initialRect.minY + resizeControl.translation.y,
- width: initialRect.width + resizeControl.translation.x,
- height: initialRect.height - resizeControl.translation.y)
-
- if keepAspectRatio {
- if abs(resizeControl.translation.x) < abs(resizeControl.translation.y) {
- rect = constrainedRectWithRectBasisOfHeight(rect)
- } else {
- rect = constrainedRectWithRectBasisOfWidth(rect)
- }
- }
- } else if resizeControl == bottomLeftCornerView {
- rect = CGRect(x: initialRect.minX + resizeControl.translation.x,
- y: initialRect.minY,
- width: initialRect.width - resizeControl.translation.x,
- height: initialRect.height + resizeControl.translation.y)
-
- if keepAspectRatio {
- var constrainedFrame: CGRect
- if abs(resizeControl.translation.x) < abs(resizeControl.translation.y) {
- constrainedFrame = constrainedRectWithRectBasisOfHeight(rect)
- } else {
- constrainedFrame = constrainedRectWithRectBasisOfWidth(rect)
- }
- constrainedFrame.origin.x -= constrainedFrame.width - rect.width
- rect = constrainedFrame
- }
- } else if resizeControl == bottomRightCornerView {
- rect = CGRect(x: initialRect.minX,
- y: initialRect.minY,
- width: initialRect.width + resizeControl.translation.x,
- height: initialRect.height + resizeControl.translation.y)
-
- if keepAspectRatio {
- if abs(resizeControl.translation.x) < abs(resizeControl.translation.y) {
- rect = constrainedRectWithRectBasisOfHeight(rect)
- } else {
- rect = constrainedRectWithRectBasisOfWidth(rect)
- }
- }
- }
-
- let minWidth = leftEdgeView.bounds.width + rightEdgeView.bounds.width
- if rect.width < minWidth {
- rect.origin.x = frame.maxX - minWidth
- rect.size.width = minWidth
- }
-
- let minHeight = topEdgeView.bounds.height + bottomEdgeView.bounds.height
- if rect.height < minHeight {
- rect.origin.y = frame.maxY - minHeight
- rect.size.height = minHeight
- }
-
- if fixedAspectRatio > 0 {
- var constraintedFrame = rect
- if rect.width < minWidth {
- constraintedFrame.size.width = rect.size.height * (minWidth / rect.size.width)
- }
- if rect.height < minHeight {
- constraintedFrame.size.height = rect.size.width * (minHeight / rect.size.height)
- }
- rect = constraintedFrame
- }
-
- return rect
- }
-
- fileprivate func constrainedRectWithRectBasisOfWidth(_ frame: CGRect) -> CGRect {
- var result = frame
- let width = frame.width
- var height = frame.height
-
- if width < height {
- height = width / fixedAspectRatio
- } else {
- height = width * fixedAspectRatio
- }
- result.size = CGSize(width: width, height: height)
- return result
- }
-
- fileprivate func constrainedRectWithRectBasisOfHeight(_ frame: CGRect) -> CGRect {
- var result = frame
- var width = frame.width
- let height = frame.height
-
- if width < height {
- width = height * fixedAspectRatio
- } else {
- width = height / fixedAspectRatio
- }
- result.size = CGSize(width: width, height: height)
- return result
- }
- }
|