diff --git a/ALCameraViewController.podspec b/ALCameraViewController.podspec index 17cd1fe7..ffedc4f6 100644 --- a/ALCameraViewController.podspec +++ b/ALCameraViewController.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "ALCameraViewController" - spec.version = "1.4.1" + spec.version = "2.0.0" spec.summary = "A camera view controller with custom image picker and image cropping." spec.source = { :git => "https://github.com/AlexLittlejohn/ALCameraViewController.git", :tag => spec.version.to_s } spec.requires_arc = true diff --git a/ALCameraViewController.xcodeproj/project.pbxproj b/ALCameraViewController.xcodeproj/project.pbxproj index 947182ed..a85be7ed 100644 --- a/ALCameraViewController.xcodeproj/project.pbxproj +++ b/ALCameraViewController.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 7AC96FA21F5B5166003E53F4 /* CroppingParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */; }; C40665441C73A47C00EB9751 /* SingleImageSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665431C73A47C00EB9751 /* SingleImageSaver.swift */; }; C40665461C73A94100EB9751 /* CameraGlobals.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665451C73A94100EB9751 /* CameraGlobals.swift */; }; C40665481C73B72D00EB9751 /* SingleImageFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665471C73B72D00EB9751 /* SingleImageFetcher.swift */; }; @@ -58,6 +59,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CroppingParameters.swift; sourceTree = ""; }; C40665431C73A47C00EB9751 /* SingleImageSaver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleImageSaver.swift; sourceTree = ""; }; C40665451C73A94100EB9751 /* CameraGlobals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraGlobals.swift; sourceTree = ""; }; C40665471C73B72D00EB9751 /* SingleImageFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleImageFetcher.swift; sourceTree = ""; }; @@ -154,6 +156,7 @@ C4D9BA441CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift */, C4D9BA461CA73163004F70F7 /* UIButtonExtensions.swift */, EBFE097C1CAF1D1A00A8C637 /* UIViewExtensions.swift */, + 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */, ); path = Utilities; sourceTree = ""; @@ -267,7 +270,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = zero; TargetAttributes = { C4829FFA1CAEB16C00541D08 = { @@ -366,6 +369,7 @@ FAB50C001B413E8C009905B9 /* PhotoLibraryViewController.swift in Sources */, FAF0586A1B317894008E5592 /* CameraShot.swift in Sources */, FAF058661B316695008E5592 /* CameraViewController.swift in Sources */, + 7AC96FA21F5B5166003E53F4 /* CroppingParameters.swift in Sources */, C4D9BA451CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift in Sources */, FAB50BFB1B413E8C009905B9 /* ImageCell.swift in Sources */, EBFE097D1CAF1D1A00A8C637 /* UIViewExtensions.swift in Sources */, @@ -438,14 +442,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -486,14 +496,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/ALCameraViewController.xcodeproj/xcshareddata/xcschemes/CameraViewController.xcscheme b/ALCameraViewController.xcodeproj/xcshareddata/xcschemes/CameraViewController.xcscheme index 9dec7dbe..f8654c4d 100644 --- a/ALCameraViewController.xcodeproj/xcshareddata/xcschemes/CameraViewController.xcscheme +++ b/ALCameraViewController.xcodeproj/xcshareddata/xcschemes/CameraViewController.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/ALCameraViewController/Utilities/CroppingParameters.swift b/ALCameraViewController/Utilities/CroppingParameters.swift new file mode 100644 index 00000000..88f90acf --- /dev/null +++ b/ALCameraViewController/Utilities/CroppingParameters.swift @@ -0,0 +1,39 @@ +// +// CroppingParameters.swift +// ALCameraViewController +// +// Created by Guillaume Bellut on 02/09/2017. +// Copyright © 2017 zero. All rights reserved. +// + +import UIKit + +public struct CroppingParameters { + + /// 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 + + /// Allow the cropping area to be moved by the user. + /// Default value is set to false. + var allowMoving: Bool + + /// Prevent the user to resize the cropping area below a minimum size. + /// Default value is (60, 60). Below this value, corner buttons will overlap. + var minimumSize: CGSize + + public init(isEnabled: Bool = false, + allowResizing: Bool = true, + allowMoving: Bool = true, + minimumSize: CGSize = CGSize(width: 60, height: 60)) { + + self.isEnabled = isEnabled + self.allowResizing = allowResizing + self.allowMoving = allowMoving + self.minimumSize = minimumSize + } +} diff --git a/ALCameraViewController/Utilities/SingleImageFetcher.swift b/ALCameraViewController/Utilities/SingleImageFetcher.swift index 9e266758..dbbb9c6a 100644 --- a/ALCameraViewController/Utilities/SingleImageFetcher.swift +++ b/ALCameraViewController/Utilities/SingleImageFetcher.swift @@ -78,12 +78,11 @@ public class SingleImageFetcher { options.resizeMode = .exact let targetWidth = floor(CGFloat(asset.pixelWidth) * cropRect.width) - let targetHeight = floor(CGFloat(asset.pixelHeight) * cropRect.height) - let dimension = max(min(targetHeight, targetWidth), 1024 * scale) - - targetSize = CGSize(width: dimension, height: dimension) + let targetHeight = floor(CGFloat(asset.pixelHeight) * cropRect.height) + + targetSize = CGSize(width: targetWidth, height: targetHeight) } - + PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, _ in if let image = image { self.success?(image) diff --git a/ALCameraViewController/ViewController/CameraViewController.swift b/ALCameraViewController/ViewController/CameraViewController.swift index a1adc0e8..f23d25bc 100644 --- a/ALCameraViewController/ViewController/CameraViewController.swift +++ b/ALCameraViewController/ViewController/CameraViewController.swift @@ -14,7 +14,7 @@ public typealias CameraViewCompletion = (UIImage?, PHAsset?) -> Void public extension CameraViewController { /// Provides an image picker wrapped inside a UINavigationController instance - public class func imagePickerViewController(croppingEnabled: Bool, completion: @escaping CameraViewCompletion) -> UINavigationController { + public class func imagePickerViewController(croppingParameters: CroppingParameters, completion: @escaping CameraViewCompletion) -> UINavigationController { let imagePicker = PhotoLibraryViewController() let navigationController = UINavigationController(rootViewController: imagePicker) @@ -24,7 +24,7 @@ public extension CameraViewController { imagePicker.onSelectionComplete = { [weak imagePicker] asset in if let asset = asset { - let confirmController = ConfirmViewController(asset: asset, allowsCropping: croppingEnabled) + let confirmController = ConfirmViewController(asset: asset, croppingParameters: croppingParameters) confirmController.onComplete = { [weak imagePicker] image, asset in if let image = image, let asset = asset { completion(image, asset) @@ -46,7 +46,7 @@ public extension CameraViewController { open class CameraViewController: UIViewController { var didUpdateViews = false - var allowCropping = false + var croppingParameters: CroppingParameters var animationRunning = false let allowVolumeButtonCapture: Bool @@ -89,7 +89,7 @@ open class CameraViewController: UIViewController { cameraView.translatesAutoresizingMaskIntoConstraints = false return cameraView }() - + let cameraOverlay : CropOverlay = { let cameraOverlay = CropOverlay() cameraOverlay.translatesAutoresizingMaskIntoConstraints = false @@ -159,13 +159,18 @@ open class CameraViewController: UIViewController { private let allowsLibraryAccess: Bool - public init(croppingEnabled: Bool, allowsLibraryAccess: Bool = true, allowsSwapCameraOrientation: Bool = true, allowVolumeButtonCapture: Bool = true, completion: @escaping CameraViewCompletion) { - self.allowsLibraryAccess = allowsLibraryAccess + public init(croppingParameters: CroppingParameters = CroppingParameters(), + allowsLibraryAccess: Bool = true, + allowsSwapCameraOrientation: Bool = true, + allowVolumeButtonCapture: Bool = true, + completion: @escaping CameraViewCompletion) { + + self.croppingParameters = croppingParameters + self.allowsLibraryAccess = allowsLibraryAccess self.allowVolumeButtonCapture = allowVolumeButtonCapture super.init(nibName: nil, bundle: nil) onCompletion = completion - allowCropping = croppingEnabled - cameraOverlay.isHidden = !allowCropping + cameraOverlay.isHidden = !croppingParameters.isEnabled libraryButton.isEnabled = allowsLibraryAccess libraryButton.isHidden = !allowsLibraryAccess swapButton.isEnabled = allowsSwapCameraOrientation @@ -539,7 +544,7 @@ open class CameraViewController: UIViewController { } internal func showLibrary() { - let imagePicker = CameraViewController.imagePickerViewController(croppingEnabled: allowCropping) { [weak self] image, asset in + let imagePicker = CameraViewController.imagePickerViewController(croppingParameters: croppingParameters) { [weak self] image, asset in defer { self?.dismiss(animated: true, completion: nil) } @@ -588,7 +593,7 @@ open class CameraViewController: UIViewController { } private func startConfirmController(uiImage: UIImage) { - let confirmViewController = ConfirmViewController(image: uiImage, allowsCropping: allowCropping) + let confirmViewController = ConfirmViewController(image: uiImage, croppingParameters: croppingParameters) confirmViewController.onComplete = { [weak self] image, asset in defer { self?.dismiss(animated: true, completion: nil) @@ -606,7 +611,7 @@ open class CameraViewController: UIViewController { } private func startConfirmController(asset: PHAsset) { - let confirmViewController = ConfirmViewController(asset: asset, allowsCropping: allowCropping) + let confirmViewController = ConfirmViewController(asset: asset, croppingParameters: croppingParameters) confirmViewController.onComplete = { [weak self] image, asset in defer { self?.dismiss(animated: true, completion: nil) diff --git a/ALCameraViewController/ViewController/ConfirmViewController.swift b/ALCameraViewController/ViewController/ConfirmViewController.swift index dba22b06..d9eccd23 100644 --- a/ALCameraViewController/ViewController/ConfirmViewController.swift +++ b/ALCameraViewController/ViewController/ConfirmViewController.swift @@ -18,33 +18,37 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { @IBOutlet weak var confirmButton: UIButton! @IBOutlet weak var centeringView: UIView! - var allowsCropping: Bool = false + var croppingParameters: CroppingParameters { + didSet { + cropOverlay.isResizable = croppingParameters.allowResizing + cropOverlay.minimumSize = croppingParameters.minimumSize + } + } + var verticalPadding: CGFloat = 30 var horizontalPadding: CGFloat = 30 public var onComplete: CameraViewCompletion? - + let asset: PHAsset? let image: UIImage? - public init(image: UIImage, allowsCropping: Bool) { - self.allowsCropping = allowsCropping + public init(image: UIImage, croppingParameters: CroppingParameters) { + self.croppingParameters = croppingParameters self.asset = nil self.image = image super.init(nibName: "ConfirmViewController", bundle: CameraGlobals.shared.bundle) } - public init(asset: PHAsset, allowsCropping: Bool) { - self.allowsCropping = allowsCropping + public init(asset: PHAsset, croppingParameters: CroppingParameters) { + self.croppingParameters = croppingParameters self.asset = asset self.image = nil super.init(nibName: "ConfirmViewController", bundle: CameraGlobals.shared.bundle) } - public required init?(coder aDecoder: NSCoder) { - asset = nil - image = nil - super.init(coder: aDecoder) + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") } public override var prefersStatusBarHidden: Bool { @@ -57,15 +61,18 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { public override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = UIColor.black scrollView.addSubview(imageView) scrollView.delegate = self scrollView.maximumZoomScale = 1 - cropOverlay.isHidden = true - + cropOverlay.isHidden = true + cropOverlay.isResizable = croppingParameters.allowResizing + cropOverlay.isMovable = croppingParameters.allowMoving + cropOverlay.minimumSize = croppingParameters.minimumSize + let spinner = showSpinner() disable() @@ -93,7 +100,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { public override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() let scale = calculateMinimumScale(view.frame.size) - let frame = allowsCropping ? cropOverlay.frame : view.bounds + let frame = croppingParameters.isEnabled ? cropOverlay.frame : view.bounds scrollView.contentInset = calculateScrollViewInsets(frame) scrollView.minimumZoomScale = scale @@ -108,7 +115,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { let scale = calculateMinimumScale(size) var frame = view.bounds - if allowsCropping { + if croppingParameters.isEnabled { frame = cropOverlay.frame let centeringFrame = centeringView.frame var origin: CGPoint @@ -139,11 +146,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } private func configureWithImage(_ image: UIImage) { - if allowsCropping { - cropOverlay.isHidden = false - } else { - cropOverlay.isHidden = true - } + cropOverlay.isHidden = !croppingParameters.isEnabled buttonActions() @@ -155,7 +158,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { private func calculateMinimumScale(_ size: CGSize) -> CGFloat { var _size = size - if allowsCropping { + if croppingParameters.isEnabled { _size = cropOverlay.frame.size } @@ -168,7 +171,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { var scale: CGFloat - if allowsCropping { + if croppingParameters.isEnabled { scale = max(scaleWidth, scaleHeight) } else { scale = min(scaleWidth, scaleHeight) @@ -185,8 +188,8 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } private func centerImageViewOnRotate() { - if allowsCropping { - let size = allowsCropping ? cropOverlay.frame.size : scrollView.frame.size + if croppingParameters.isEnabled { + let size = cropOverlay.frame.size let scrollInsets = scrollView.contentInset let imageSize = imageView.frame.size var contentOffset = CGPoint(x: -scrollInsets.left, y: -scrollInsets.top) @@ -197,7 +200,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } private func centerScrollViewContents() { - let size = allowsCropping ? cropOverlay.frame.size : scrollView.frame.size + let size = croppingParameters.isEnabled ? cropOverlay.frame.size : scrollView.frame.size let imageSize = imageView.frame.size var imageOrigin = CGPoint.zero @@ -245,7 +248,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { self?.showNoImageScreen(error) } .setAsset(asset) - if allowsCropping { + if croppingParameters.isEnabled { let rect = normalizedRect(makeProportionalCropRect(), orientation: image.imageOrientation) fetcher = fetcher.setCropRect(rect) } @@ -254,7 +257,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } else { var newImage = image - if allowsCropping { + if croppingParameters.isEnabled { let cropRect = makeProportionalCropRect() let resizedCropRect = CGRect(x: (image.size.width) * cropRect.origin.x, y: (image.size.height) * cropRect.origin.y, @@ -311,7 +314,10 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } private func makeProportionalCropRect() -> CGRect { - var cropRect = cropOverlay.frame + var cropRect = CGRect(x: cropOverlay.frame.origin.x + cropOverlay.outterGap, + y: cropOverlay.frame.origin.y + cropOverlay.outterGap, + width: cropOverlay.frame.size.width - 2 * cropOverlay.outterGap, + height: cropOverlay.frame.size.height - 2 * cropOverlay.outterGap) cropRect.origin.x += scrollView.contentOffset.x cropRect.origin.y += scrollView.contentOffset.y diff --git a/ALCameraViewController/ViewController/ConfirmViewController.xib b/ALCameraViewController/ViewController/ConfirmViewController.xib index fd8a355a..c3f3a9dc 100644 --- a/ALCameraViewController/ViewController/ConfirmViewController.xib +++ b/ALCameraViewController/ViewController/ConfirmViewController.xib @@ -1,8 +1,13 @@ - - + + + + + - + + + @@ -17,47 +22,41 @@ - + - - - - - - - + - - - - - - - - - - - + diff --git a/ALCameraViewController/Views/CropOverlay.swift b/ALCameraViewController/Views/CropOverlay.swift index e330223f..dde94409 100644 --- a/ALCameraViewController/Views/CropOverlay.swift +++ b/ALCameraViewController/Views/CropOverlay.swift @@ -18,11 +18,26 @@ internal class CropOverlay: UIView { var topRightCornerLines = [UIView]() var bottomLeftCornerLines = [UIView]() var bottomRightCornerLines = [UIView]() - - let cornerDepth: CGFloat = 3 - let cornerWidth: CGFloat = 20 + + var cornerButtons = [UIButton]() + + let cornerLineDepth: CGFloat = 3 + let cornerLineWidth: CGFloat = 22.5 + var cornerButtonWidth: CGFloat { + return self.cornerLineWidth * 2 + } + let lineWidth: CGFloat = 1 - + + let outterGapRatio: CGFloat = 1/3 + var outterGap: CGFloat { + return self.cornerButtonWidth * self.outterGapRatio + } + + var isResizable: Bool = false + var isMovable: Bool = false + var minimumSize: CGSize = CGSize.zero + internal override init(frame: CGRect) { super.init(frame: frame) createLines() @@ -40,16 +55,16 @@ internal class CropOverlay: UIView { var lineFrame: CGRect switch (i) { case 0: - lineFrame = CGRect(x: 0, y: 0, width: bounds.width, height: lineWidth) + lineFrame = CGRect(x: outterGap, y: outterGap, width: bounds.width - outterGap * 2, height: lineWidth) break case 1: - lineFrame = CGRect(x: bounds.width - lineWidth, y: 0, width: lineWidth, height: bounds.height) + lineFrame = CGRect(x: bounds.width - lineWidth - outterGap, y: outterGap, width: lineWidth, height: bounds.height - outterGap * 2) break case 2: - lineFrame = CGRect(x: 0, y: bounds.height - lineWidth, width: bounds.width, height: lineWidth) + lineFrame = CGRect(x: outterGap, y: bounds.height - lineWidth - outterGap, width: bounds.width - outterGap * 2, height: lineWidth) break case 3: - lineFrame = CGRect(x: 0, y: 0, width: lineWidth, height: bounds.height) + lineFrame = CGRect(x: outterGap, y: outterGap, width: lineWidth, height: bounds.height - outterGap * 2) break default: lineFrame = CGRect.zero @@ -62,51 +77,58 @@ internal class CropOverlay: UIView { let corners = [topLeftCornerLines, topRightCornerLines, bottomLeftCornerLines, bottomRightCornerLines] for i in 0.. UIView { @@ -127,4 +152,51 @@ internal class CropOverlay: UIView { addSubview(line) return line } + + func createButton() -> UIButton { + let button = UIButton() + button.backgroundColor = UIColor.clear + + let dragGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(moveCropOverlay)) + button.addGestureRecognizer(dragGestureRecognizer) + + addSubview(button) + return button + } + + func moveCropOverlay(gestureRecognizer: UIPanGestureRecognizer) { + if isResizable, 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 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 + layoutSubviews() + + gestureRecognizer.setTranslation(CGPoint.zero, in: self) + } + } else if isMovable { + if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { + let translation = gestureRecognizer.translation(in: self) + + gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y) + gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self) + } + } + } } diff --git a/Example/ViewController.swift b/Example/ViewController.swift index ef160478..e4c6aa1b 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -10,17 +10,28 @@ import UIKit class ViewController: UIViewController { - var croppingEnabled: Bool = false var libraryEnabled: Bool = true + var croppingEnabled: Bool = false + var allowResizing: Bool = true + var allowMoving: Bool = false + var minimumSize: CGSize = CGSize(width: 60, height: 60) + + var croppingParameters: CroppingParameters { + return CroppingParameters(isEnabled: croppingEnabled, allowResizing: allowResizing, allowMoving: allowMoving, minimumSize: minimumSize) + } @IBOutlet weak var imageView: UIImageView! - + @IBOutlet weak var croppingParametersView: UIView! + @IBOutlet weak var minimumSizeLabel: UILabel! + override func viewDidLoad() { super.viewDidLoad() + + self.imageView.contentMode = .scaleAspectFit } - @IBAction func openCamera(_ sender: AnyObject) { - let cameraViewController = CameraViewController(croppingEnabled: croppingEnabled, allowsLibraryAccess: libraryEnabled) { [weak self] image, asset in + @IBAction func openCamera(_ sender: Any) { + let cameraViewController = CameraViewController(croppingParameters: croppingParameters, allowsLibraryAccess: libraryEnabled) { [weak self] image, asset in self?.imageView.image = image self?.dismiss(animated: true, completion: nil) } @@ -28,8 +39,8 @@ class ViewController: UIViewController { present(cameraViewController, animated: true, completion: nil) } - @IBAction func openLibrary(_ sender: AnyObject) { - let libraryViewController = CameraViewController.imagePickerViewController(croppingEnabled: croppingEnabled) { [weak self] image, asset in + @IBAction func openLibrary(_ sender: Any) { + let libraryViewController = CameraViewController.imagePickerViewController(croppingParameters: croppingParameters) { [weak self] image, asset in self?.imageView.image = image self?.dismiss(animated: true, completion: nil) } @@ -37,12 +48,27 @@ class ViewController: UIViewController { present(libraryViewController, animated: true, completion: nil) } - @IBAction func libraryChanged(_ sender: AnyObject) { + @IBAction func libraryChanged(_ sender: Any) { libraryEnabled = !libraryEnabled } - @IBAction func croppingChanged(_ sender: AnyObject) { - croppingEnabled = !croppingEnabled + @IBAction func croppingChanged(_ sender: UISwitch) { + croppingEnabled = sender.isOn + croppingParametersView.isHidden = !sender.isOn + } + + @IBAction func resizingChanged(_ sender: UISwitch) { + allowResizing = sender.isOn + } + + @IBAction func movingChanged(_ sender: UISwitch) { + allowMoving = sender.isOn + } + + @IBAction func minimumSizeChanged(_ sender: UISlider) { + let newValue = sender.value + minimumSize = CGSize(width: CGFloat(newValue), height: CGFloat(newValue)) + minimumSizeLabel.text = "Minimum size: \(newValue.rounded())" } } diff --git a/Example/ViewController.xib b/Example/ViewController.xib index dde3307b..cb3d4f40 100644 --- a/Example/ViewController.xib +++ b/Example/ViewController.xib @@ -1,26 +1,40 @@ - - + + + + + - + + + + AppleSDGothicNeo-Regular + + + + - - + + - + + + + + + + + + +