Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Added rectangular and square cropping frame support. #220

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions ALCameraViewController/Utilities/CroppingParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@
import UIKit

public struct CroppingParameters {

public enum ResizingMode {
case none
case rectangle
case square
}

/// Enable the cropping feature.
/// Default value is set to false.
var isEnabled: Bool

/// Allow the cropping area to be resized by the user.
/// Default value is set to true.
var allowResizing: Bool
/// Select resizing mode for the cropping frame.
/// Use .rectangle for free form resizing, .square for square resizing and .none if you want to disable resizing
var resizingMode: ResizingMode

/// Allow the cropping area to be moved by the user.
/// Default value is set to false.
Expand All @@ -27,12 +33,12 @@ public struct CroppingParameters {
var minimumSize: CGSize

public init(isEnabled: Bool = false,
allowResizing: Bool = true,
resizingMode: ResizingMode = .rectangle,
allowMoving: Bool = true,
minimumSize: CGSize = CGSize(width: 60, height: 60)) {

self.isEnabled = isEnabled
self.allowResizing = allowResizing
self.resizingMode = resizingMode
self.allowMoving = allowMoving
self.minimumSize = minimumSize
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate {

var croppingParameters: CroppingParameters {
didSet {
cropOverlay.isResizable = croppingParameters.allowResizing
cropOverlay.resizingMode = croppingParameters.resizingMode
cropOverlay.minimumSize = croppingParameters.minimumSize
}
}
Expand Down Expand Up @@ -69,7 +69,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate {
scrollView.maximumZoomScale = 1

cropOverlay.isHidden = true
cropOverlay.isResizable = croppingParameters.allowResizing
cropOverlay.resizingMode = croppingParameters.resizingMode
cropOverlay.isMovable = croppingParameters.allowMoving
cropOverlay.minimumSize = croppingParameters.minimumSize

Expand Down
87 changes: 65 additions & 22 deletions ALCameraViewController/Views/CropOverlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal class CropOverlay: UIView {
return self.cornerButtonWidth * self.outterGapRatio
}

var isResizable: Bool = false
var resizingMode: CroppingParameters.ResizingMode = .none
var isMovable: Bool = false
var minimumSize: CGSize = CGSize.zero

Expand Down Expand Up @@ -130,7 +130,6 @@ internal class CropOverlay: UIView {
}

func createLines() {

outerLines = [createLine(), createLine(), createLine(), createLine()]
horizontalLines = [createLine(), createLine()]
verticalLines = [createLine(), createLine()]
Expand Down Expand Up @@ -164,28 +163,22 @@ internal class CropOverlay: UIView {
return button
}

@objc func moveCropOverlay(gestureRecognizer: UIPanGestureRecognizer) {
if isResizable, let button = gestureRecognizer.view as? UIButton {
func moveCropOverlay(gestureRecognizer: UIPanGestureRecognizer) {
if resizingMode != .none, let button = gestureRecognizer.view as? UIButton {
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
let translation = gestureRecognizer.translation(in: self)

var newFrame: CGRect

switch button {
case cornerButtons[0]: // Top Left
newFrame = CGRect(x: frame.origin.x + translation.x, y: frame.origin.y + translation.y, width: frame.size.width - translation.x, height: frame.size.height - translation.y)
case cornerButtons[1]: // Top Right
newFrame = CGRect(x: frame.origin.x, y: frame.origin.y + translation.y, width: frame.size.width + translation.x, height: frame.size.height - translation.y)
case cornerButtons[2]: // Bottom Left
newFrame = CGRect(x: frame.origin.x + translation.x, y: frame.origin.y, width: frame.size.width - translation.x, height: frame.size.height + translation.y)
case cornerButtons[3]: // Bottom Right
newFrame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width + translation.x, height: frame.size.height + translation.y)
default:
newFrame = CGRect.zero
}
let translation = gestureRecognizer.translation(in: self)

let newFrame: CGRect
if resizingMode == .rectangle {
newFrame = getNewRectangleFrame(translation: translation, button: button)
} else {
newFrame = getNewSquareFrame(translation: translation, button: button)
}

let minimumFrame = CGRect(x: newFrame.origin.x, y: newFrame.origin.y, width: max(newFrame.size.width, minimumSize.width + 2 * outterGap), height: max(newFrame.size.height, minimumSize.height + 2 * outterGap))
frame = minimumFrame

frame = minimumFrame

layoutSubviews()

gestureRecognizer.setTranslation(CGPoint.zero, in: self)
Expand All @@ -199,11 +192,61 @@ internal class CropOverlay: UIView {
}
}
}

private func getNewRectangleFrame(translation: CGPoint, button: UIButton) -> CGRect {
switch button {
case cornerButtons[0]: // Top Left
return CGRect(x: frame.origin.x + translation.x, y: frame.origin.y + translation.y, width: frame.size.width - translation.x, height: frame.size.height - translation.y)
case cornerButtons[1]: // Top Right
return CGRect(x: frame.origin.x, y: frame.origin.y + translation.y, width: frame.size.width + translation.x, height: frame.size.height - translation.y)
case cornerButtons[2]: // Bottom Left
return CGRect(x: frame.origin.x + translation.x, y: frame.origin.y, width: frame.size.width - translation.x, height: frame.size.height + translation.y)
case cornerButtons[3]: // Bottom Right
return CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width + translation.x, height: frame.size.height + translation.y)
default:
return CGRect.zero
}
}

private func getNewSquareFrame(translation: CGPoint, button: UIButton) -> CGRect {
let distance = max(abs(translation.x), abs(translation.y))
let dx = translation.x < 0 ? -distance : distance
let dy = translation.y < 0 ? -distance : distance

switch button {
case cornerButtons[0]: // Top Left
guard dx>0 && dy>0 || dx<0 && dy<0 else {
return frame
}

return CGRect(x: frame.origin.x + dx, y: frame.origin.y + dy, width: frame.size.width - dx, height: frame.size.height - dy)
case cornerButtons[1]: // Top Right
guard dx>0 && dy<0 || dx<0 && dy>0 else {
return frame
}

return CGRect(x: frame.origin.x, y: frame.origin.y + dy, width: frame.size.width + dx, height: frame.size.height - dy)
case cornerButtons[2]: // Bottom Left
guard dx<0 && dy>0 || dx>0 && dy<0 else {
return frame
}

return CGRect(x: frame.origin.x + dx, y: frame.origin.y, width: frame.size.width - dx, height: frame.size.height + dy)
case cornerButtons[3]: // Bottom Right
guard dx>0 && dy>0 || dx<0 && dy<0 else {
return frame
}

return CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width + dx, height: frame.size.height + dy)
default:
return CGRect.zero
}
}

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)

if !isMovable && isResizable && view != nil {
if !isMovable && resizingMode != .none && view != nil {
let isButton = cornerButtons.reduce(false) { $1.hitTest(convert(point, to: $1), with: event) != nil || $0 }
if !isButton {
return nil
Expand Down
3 changes: 2 additions & 1 deletion Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class ViewController: UIViewController {
var minimumSize: CGSize = CGSize(width: 60, height: 60)

var croppingParameters: CroppingParameters {
return CroppingParameters(isEnabled: croppingEnabled, allowResizing: allowResizing, allowMoving: allowMoving, minimumSize: minimumSize)
let resizingMode: CroppingParameters.ResizingMode = allowResizing ? .square : .none
return CroppingParameters(isEnabled: croppingEnabled, resizingMode: resizingMode, allowMoving: allowMoving, minimumSize: minimumSize)
}

@IBOutlet weak var imageView: UIImageView!
Expand Down