From 897a32144a3aadabc764e01202c9cdb7225498cb Mon Sep 17 00:00:00 2001 From: Adil Soomro Date: Fri, 24 Feb 2017 23:41:51 +0500 Subject: [PATCH 1/5] Upgrade to swift 3, Xcode 8.2.1 --- .gitignore | 2 + Resizable.xcodeproj/project.pbxproj | 22 +++++- Resizable/AppDelegate.swift | 12 +-- Resizable/DragHandle.swift | 14 ++-- .../AppIcon.appiconset/Contents.json | 25 ++++++ Resizable/Info.plist | 2 +- Resizable/ResizableView.swift | 78 +++++++++---------- Resizable/UIView+Transform.swift | 26 +++---- Resizable/ViewController.swift | 8 +- ResizableTests/Info.plist | 2 +- ResizableTests/ResizableTests.swift | 2 +- 11 files changed, 120 insertions(+), 73 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bf5374 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Resizable.xcodeproj/xcuserdata +Resizable.xcodeproj/project.xcworkspace/xcuserdata diff --git a/Resizable.xcodeproj/project.pbxproj b/Resizable.xcodeproj/project.pbxproj index 11d7b71..6d73e24 100644 --- a/Resizable.xcodeproj/project.pbxproj +++ b/Resizable.xcodeproj/project.pbxproj @@ -162,14 +162,16 @@ 82982C9E19BAE5EA00D257C1 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0600; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = Caroline; TargetAttributes = { 82982CA519BAE5EA00D257C1 = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0820; }; 82982CB719BAE5EA00D257C1 = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0820; TestTargetID = 82982CA519BAE5EA00D257C1; }; }; @@ -268,15 +270,19 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -310,8 +316,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -319,6 +327,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -328,6 +337,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -339,7 +349,9 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = Resizable/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -350,7 +362,9 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = Resizable/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -368,7 +382,9 @@ ); INFOPLIST_FILE = ResizableTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Resizable.app/Resizable"; }; name = Debug; @@ -383,7 +399,9 @@ ); INFOPLIST_FILE = ResizableTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Resizable.app/Resizable"; }; name = Release; @@ -407,6 +425,7 @@ 82982CC419BAE5EA00D257C1 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 82982CC519BAE5EA00D257C1 /* Build configuration list for PBXNativeTarget "ResizableTests" */ = { isa = XCConfigurationList; @@ -415,6 +434,7 @@ 82982CC719BAE5EA00D257C1 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Resizable/AppDelegate.swift b/Resizable/AppDelegate.swift index d48d70f..f436318 100644 --- a/Resizable/AppDelegate.swift +++ b/Resizable/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/Resizable/DragHandle.swift b/Resizable/DragHandle.swift index 72a29ff..86b4660 100644 --- a/Resizable/DragHandle.swift +++ b/Resizable/DragHandle.swift @@ -12,8 +12,8 @@ import UIKit class DragHandle: UIView { - var fillColor = UIColor.darkGrayColor() - var strokeColor = UIColor.lightGrayColor() + var fillColor = UIColor.darkGray + var strokeColor = UIColor.lightGray var strokeWidth:CGFloat = 2.0 required init(coder aDecoder: NSCoder) { @@ -21,17 +21,17 @@ class DragHandle: UIView { } init(fillColor:UIColor, strokeColor:UIColor, strokeWidth width:CGFloat = 2.0) { - super.init(frame:CGRectMake(0, 0, diameter, diameter)) + super.init(frame:CGRect(x: 0, y: 0, width: diameter, height: diameter)) self.fillColor = fillColor self.strokeColor = strokeColor self.strokeWidth = width - self.backgroundColor = UIColor.clearColor() + self.backgroundColor = UIColor.clear } - override func drawRect(rect: CGRect) + override func draw(_ rect: CGRect) { - super.drawRect(rect) - var handlePath = UIBezierPath(ovalInRect: CGRectInset(rect, 10 + strokeWidth, 10 + strokeWidth)) + super.draw(rect) + let handlePath = UIBezierPath(ovalIn: rect.insetBy(dx: 10 + strokeWidth, dy: 10 + strokeWidth)) fillColor.setFill() handlePath.fill() strokeColor.setStroke() diff --git a/Resizable/Images.xcassets/AppIcon.appiconset/Contents.json b/Resizable/Images.xcassets/AppIcon.appiconset/Contents.json index a396706..b8236c6 100644 --- a/Resizable/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Resizable/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,19 +1,44 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" } ], "info" : { diff --git a/Resizable/Info.plist b/Resizable/Info.plist index 9bc3ce0..dd791df 100644 --- a/Resizable/Info.plist +++ b/Resizable/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.caroline.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Resizable/ResizableView.swift b/Resizable/ResizableView.swift index 78c6eae..c9d7597 100644 --- a/Resizable/ResizableView.swift +++ b/Resizable/ResizableView.swift @@ -20,10 +20,10 @@ class ResizableView: UIView { override func didMoveToSuperview() { - let resizeFillColor = UIColor.cyanColor() - let resizeStrokeColor = UIColor.blackColor() - let rotateFillColor = UIColor.orangeColor() - let rotateStrokeColor = UIColor.blackColor() + let resizeFillColor = UIColor.cyan + let resizeStrokeColor = UIColor.black + let rotateFillColor = UIColor.orange + let rotateStrokeColor = UIColor.black topLeft = DragHandle(fillColor:resizeFillColor, strokeColor: resizeStrokeColor) topRight = DragHandle(fillColor:resizeFillColor, strokeColor: resizeStrokeColor) bottomLeft = DragHandle(fillColor:resizeFillColor, strokeColor: resizeStrokeColor) @@ -41,17 +41,17 @@ class ResizableView: UIView { self.layer.addSublayer(rotateLine) - var pan = UIPanGestureRecognizer(target: self, action: "handlePan:") + var pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handlePan(_:))) topLeft.addGestureRecognizer(pan) - pan = UIPanGestureRecognizer(target: self, action: "handlePan:") + pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handlePan(_:))) topRight.addGestureRecognizer(pan) - pan = UIPanGestureRecognizer(target: self, action: "handlePan:") + pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handlePan(_:))) bottomLeft.addGestureRecognizer(pan) - pan = UIPanGestureRecognizer(target: self, action: "handlePan:") + pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handlePan(_:))) bottomRight.addGestureRecognizer(pan) - pan = UIPanGestureRecognizer(target: self, action: "handleRotate:") + pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handleRotate(_:))) rotateHandle.addGestureRecognizer(pan) - pan = UIPanGestureRecognizer(target: self, action: "handleMove:") + pan = UIPanGestureRecognizer(target: self, action: #selector(ResizableView.handleMove(_:))) self.addGestureRecognizer(pan) self.updateDragHandles() @@ -67,19 +67,19 @@ class ResizableView: UIView { //MARK: - Gesture Methods - func handleMove(gesture:UIPanGestureRecognizer) { - let translation = gesture.translationInView(self.superview!) + func handleMove(_ gesture:UIPanGestureRecognizer) { + let translation = gesture.translation(in: self.superview!) var center = self.center center.x += translation.x center.y += translation.y self.center = center - gesture.setTranslation(CGPointZero, inView: self.superview!) + gesture.setTranslation(CGPoint.zero, in: self.superview!) updateDragHandles() } - func angleBetweenPoints(startPoint:CGPoint, endPoint:CGPoint) -> CGFloat { + func angleBetweenPoints(_ startPoint:CGPoint, endPoint:CGPoint) -> CGFloat { let a = startPoint.x - self.center.x let b = startPoint.y - self.center.y let c = endPoint.x - self.center.x @@ -90,68 +90,68 @@ class ResizableView: UIView { } - func drawRotateLine(fromPoint:CGPoint, toPoint:CGPoint) { - var linePath = UIBezierPath() - linePath.moveToPoint(fromPoint) - linePath.addLineToPoint(toPoint) - rotateLine.path = linePath.CGPath + func drawRotateLine(_ fromPoint:CGPoint, toPoint:CGPoint) { + let linePath = UIBezierPath() + linePath.move(to: fromPoint) + linePath.addLine(to: toPoint) + rotateLine.path = linePath.cgPath rotateLine.fillColor = nil - rotateLine.strokeColor = UIColor.orangeColor().CGColor + rotateLine.strokeColor = UIColor.orange.cgColor rotateLine.lineWidth = 2.0 rotateLine.opacity = 1.0 } - func handleRotate(gesture:UIPanGestureRecognizer) { + func handleRotate(_ gesture:UIPanGestureRecognizer) { switch gesture.state { - case .Began: + case .began: previousLocation = rotateHandle.center - self.drawRotateLine(CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2), toPoint:CGPointMake(self.bounds.size.width + diameter, self.bounds.size.height/2)) - case .Ended: + self.drawRotateLine(CGPoint(x: self.bounds.size.width/2, y: self.bounds.size.height/2), toPoint:CGPoint(x: self.bounds.size.width + diameter, y: self.bounds.size.height/2)) + case .ended: self.rotateLine.opacity = 0.0 default:() } - let location = gesture.locationInView(self.superview!) + let location = gesture.location(in: self.superview!) let angle = angleBetweenPoints(previousLocation, endPoint: location) - self.transform = CGAffineTransformRotate(self.transform, angle) + self.transform = self.transform.rotated(by: angle) previousLocation = location self.updateDragHandles() } - func handlePan(gesture:UIPanGestureRecognizer) { - var translation = gesture.translationInView(self) + func handlePan(_ gesture:UIPanGestureRecognizer) { + let translation = gesture.translation(in: self) switch gesture.view! { case topLeft: - if gesture.state == .Began { - self.setAnchorPoint(CGPointMake(1, 1)) + if gesture.state == .began { + self.setAnchorPoint(CGPoint(x: 1, y: 1)) } self.bounds.size.width -= translation.x self.bounds.size.height -= translation.y case topRight: - if gesture.state == .Began { - self.setAnchorPoint(CGPointMake(0, 1)) + if gesture.state == .began { + self.setAnchorPoint(CGPoint(x: 0, y: 1)) } self.bounds.size.width += translation.x self.bounds.size.height -= translation.y case bottomLeft: - if gesture.state == .Began { - self.setAnchorPoint(CGPointMake(1, 0)) + if gesture.state == .began { + self.setAnchorPoint(CGPoint(x: 1, y: 0)) } self.bounds.size.width -= translation.x self.bounds.size.height += translation.y case bottomRight: - if gesture.state == .Began { - self.setAnchorPoint(CGPointZero) + if gesture.state == .began { + self.setAnchorPoint(CGPoint.zero) } self.bounds.size.width += translation.x self.bounds.size.height += translation.y default:() } - gesture.setTranslation(CGPointZero, inView: self) + gesture.setTranslation(CGPoint.zero, in: self) updateDragHandles() - if gesture.state == .Ended { - self.setAnchorPoint(CGPointMake(0.5, 0.5)) + if gesture.state == .ended { + self.setAnchorPoint(CGPoint(x: 0.5, y: 0.5)) } } } diff --git a/Resizable/UIView+Transform.swift b/Resizable/UIView+Transform.swift index c1dfe22..8ab1e09 100644 --- a/Resizable/UIView+Transform.swift +++ b/Resizable/UIView+Transform.swift @@ -15,24 +15,24 @@ import UIKit extension UIView { - func offsetPointToParentCoordinates(point: CGPoint) -> CGPoint { - return CGPointMake(point.x + self.center.x, point.y + self.center.y) + func offsetPointToParentCoordinates(_ point: CGPoint) -> CGPoint { + return CGPoint(x: point.x + self.center.x, y: point.y + self.center.y) } - func pointInViewCenterTerms(point:CGPoint) -> CGPoint { - return CGPointMake(point.x - self.center.x, point.y - self.center.y) + func pointInViewCenterTerms(_ point:CGPoint) -> CGPoint { + return CGPoint(x: point.x - self.center.x, y: point.y - self.center.y) } - func pointInTransformedView(point: CGPoint) -> CGPoint { + func pointInTransformedView(_ point: CGPoint) -> CGPoint { let offsetItem = self.pointInViewCenterTerms(point) - let updatedItem = CGPointApplyAffineTransform(offsetItem, self.transform) + let updatedItem = offsetItem.applying(self.transform) let finalItem = self.offsetPointToParentCoordinates(updatedItem) return finalItem } func originalFrame() -> CGRect { let currentTransform = self.transform - self.transform = CGAffineTransformIdentity + self.transform = CGAffineTransform.identity let originalFrame = self.frame self.transform = currentTransform return originalFrame @@ -77,12 +77,12 @@ extension UIView { return self.pointInTransformedView(point) } - func setAnchorPoint(anchorPoint:CGPoint) { - var newPoint = CGPointMake(self.bounds.size.width * anchorPoint.x, self.bounds.size.height * anchorPoint.y) - var oldPoint = CGPointMake(self.bounds.size.width * self.layer.anchorPoint.x, self.bounds.size.height * self.layer.anchorPoint.y) + func setAnchorPoint(_ anchorPoint:CGPoint) { + var newPoint = CGPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y) + var oldPoint = CGPoint(x: self.bounds.size.width * self.layer.anchorPoint.x, y: self.bounds.size.height * self.layer.anchorPoint.y) - newPoint = CGPointApplyAffineTransform(newPoint, self.transform) - oldPoint = CGPointApplyAffineTransform(oldPoint, self.transform) + newPoint = newPoint.applying(self.transform) + oldPoint = oldPoint.applying(self.transform) var position = self.layer.position position.x -= oldPoint.x @@ -94,4 +94,4 @@ extension UIView { self.layer.anchorPoint = anchorPoint } -} \ No newline at end of file +} diff --git a/Resizable/ViewController.swift b/Resizable/ViewController.swift index 0d56118..ffa0a0c 100644 --- a/Resizable/ViewController.swift +++ b/Resizable/ViewController.swift @@ -12,10 +12,10 @@ import QuartzCore class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - var resizableView = ResizableView(frame: CGRectMake(60, 100, 200, 200)) - resizableView.backgroundColor = UIColor.purpleColor() - resizableView.transform = CGAffineTransformMakeRotation(0.3) - resizableView.center = CGPointMake(160, 200) + let resizableView = ResizableView(frame: CGRect(x: 60, y: 100, width: 200, height: 200)) + resizableView.backgroundColor = UIColor.purple + resizableView.transform = CGAffineTransform(rotationAngle: 0.3) + resizableView.center = CGPoint(x: 160, y: 200) self.view.addSubview(resizableView) } } diff --git a/ResizableTests/Info.plist b/ResizableTests/Info.plist index 6e1bebb..ba72822 100644 --- a/ResizableTests/Info.plist +++ b/ResizableTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.caroline.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/ResizableTests/ResizableTests.swift b/ResizableTests/ResizableTests.swift index dd9b561..e0eb218 100644 --- a/ResizableTests/ResizableTests.swift +++ b/ResizableTests/ResizableTests.swift @@ -28,7 +28,7 @@ class ResizableTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock() { + self.measure() { // Put the code you want to measure the time of here. } } From 92c65a48e125531d3053c82a26279d0962c2b174 Mon Sep 17 00:00:00 2001 From: Adil Soomro Date: Fri, 24 Feb 2017 23:42:26 +0500 Subject: [PATCH 2/5] Added a resize dotted border view. --- Resizable.xcodeproj/project.pbxproj | 10 ++++-- Resizable/Info.plist | 2 ++ Resizable/LaunchScreen.xib | 46 +++++++++++++++++++++++++++ Resizable/ResizableView.swift | 10 +++++- Resizable/ResizeBorder.swift | 49 +++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 Resizable/LaunchScreen.xib create mode 100755 Resizable/ResizeBorder.swift diff --git a/Resizable.xcodeproj/project.pbxproj b/Resizable.xcodeproj/project.pbxproj index 6d73e24..db16792 100644 --- a/Resizable.xcodeproj/project.pbxproj +++ b/Resizable.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 82982CC919BAE60C00D257C1 /* ResizableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82982CC819BAE60C00D257C1 /* ResizableView.swift */; }; 82982CCB19BB263100D257C1 /* UIView+Transform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82982CCA19BB263100D257C1 /* UIView+Transform.swift */; }; 82982CCD19BBDAE400D257C1 /* DragHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82982CCC19BBDAE400D257C1 /* DragHandle.swift */; }; + CBE5B5561E60B22300E7A142 /* ResizeBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBE5B5551E60B22300E7A142 /* ResizeBorder.swift */; }; + CBE5B55A1E60B41200E7A142 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE5B5591E60B41200E7A142 /* LaunchScreen.xib */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,6 +42,8 @@ 82982CC819BAE60C00D257C1 /* ResizableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizableView.swift; sourceTree = ""; }; 82982CCA19BB263100D257C1 /* UIView+Transform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Transform.swift"; sourceTree = ""; }; 82982CCC19BBDAE400D257C1 /* DragHandle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragHandle.swift; sourceTree = ""; }; + CBE5B5551E60B22300E7A142 /* ResizeBorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizeBorder.swift; sourceTree = ""; }; + CBE5B5591E60B41200E7A142 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -81,12 +85,14 @@ 82982CA819BAE5EA00D257C1 /* Resizable */ = { isa = PBXGroup; children = ( + CBE5B5551E60B22300E7A142 /* ResizeBorder.swift */, 82982CAB19BAE5EA00D257C1 /* AppDelegate.swift */, 82982CAD19BAE5EA00D257C1 /* ViewController.swift */, 82982CC819BAE60C00D257C1 /* ResizableView.swift */, 82982CCC19BBDAE400D257C1 /* DragHandle.swift */, 82982CCA19BB263100D257C1 /* UIView+Transform.swift */, 82982CAF19BAE5EA00D257C1 /* Main.storyboard */, + CBE5B5591E60B41200E7A142 /* LaunchScreen.xib */, 82982CB219BAE5EA00D257C1 /* Images.xcassets */, 82982CA919BAE5EA00D257C1 /* Supporting Files */, ); @@ -200,6 +206,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + CBE5B55A1E60B41200E7A142 /* LaunchScreen.xib in Resources */, 82982CB119BAE5EA00D257C1 /* Main.storyboard in Resources */, 82982CB319BAE5EA00D257C1 /* Images.xcassets in Resources */, ); @@ -224,6 +231,7 @@ 82982CAC19BAE5EA00D257C1 /* AppDelegate.swift in Sources */, 82982CC919BAE60C00D257C1 /* ResizableView.swift in Sources */, 82982CCB19BB263100D257C1 /* UIView+Transform.swift in Sources */, + CBE5B5561E60B22300E7A142 /* ResizeBorder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -346,7 +354,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = Resizable/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; @@ -359,7 +366,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = Resizable/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.caroline.$(PRODUCT_NAME:rfc1034identifier)"; diff --git a/Resizable/Info.plist b/Resizable/Info.plist index dd791df..6905cc6 100644 --- a/Resizable/Info.plist +++ b/Resizable/Info.plist @@ -22,6 +22,8 @@ 1 LSRequiresIPhoneOS + UILaunchStoryboardName + LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities diff --git a/Resizable/LaunchScreen.xib b/Resizable/LaunchScreen.xib new file mode 100644 index 0000000..133d94a --- /dev/null +++ b/Resizable/LaunchScreen.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resizable/ResizableView.swift b/Resizable/ResizableView.swift index c9d7597..1f9d2c4 100644 --- a/Resizable/ResizableView.swift +++ b/Resizable/ResizableView.swift @@ -15,7 +15,8 @@ class ResizableView: UIView { var bottomLeft:DragHandle! var bottomRight:DragHandle! var rotateHandle:DragHandle! - var previousLocation = CGPointZero + var borderView:ResizeBorder! + var previousLocation = CGPoint.zero var rotateLine = CAShapeLayer() @@ -33,6 +34,10 @@ class ResizableView: UIView { rotateLine.opacity = 0.0 rotateLine.lineDashPattern = [3,2] + borderView = ResizeBorder(frame:self.bounds) + borderView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.addSubview(borderView) + superview?.addSubview(topLeft) superview?.addSubview(topRight) superview?.addSubview(bottomLeft) @@ -63,6 +68,9 @@ class ResizableView: UIView { bottomLeft.center = self.transformedBottomLeft() bottomRight.center = self.transformedBottomRight() rotateHandle.center = self.transformedRotateHandle() + + borderView.bounds = self.bounds + borderView.setNeedsDisplay() } //MARK: - Gesture Methods diff --git a/Resizable/ResizeBorder.swift b/Resizable/ResizeBorder.swift new file mode 100755 index 0000000..b214ffb --- /dev/null +++ b/Resizable/ResizeBorder.swift @@ -0,0 +1,49 @@ +// +// ResizeBorder.swift +// Resizable +// +// Created by Adil Soomro on 7/02/2017. +// Copyright (c) 2017 BooleanBites Ltd. All rights reserved. +// + + + +import UIKit + +let dash1: CGFloat = 2.0 +let dash2: CGFloat = 4.0 + +let lineWidth: CGFloat = 2.5 + +let dash:[CGFloat] = [dash1, dash2] + +class ResizeBorder: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = UIColor.clear + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.backgroundColor = UIColor.clear + } + + override func draw(_ rect: CGRect) + { + + + let context = UIGraphicsGetCurrentContext(); + context!.saveGState(); + + context!.setLineWidth(lineWidth); + + + context?.setLineDash(phase: 0.0, lengths: dash) + + context!.setStrokeColor(UIColor.black.cgColor); + context!.addRect(self.bounds); + context!.strokePath(); + + context!.restoreGState(); + } +} From d26dcb08a8e7d827fe10a22dbc4f0d03eb939b32 Mon Sep 17 00:00:00 2001 From: Adil Soomro Date: Fri, 24 Feb 2017 23:47:06 +0500 Subject: [PATCH 3/5] Added a screenshot --- Resizable/ViewController.swift | 3 +-- Sample.png | Bin 0 -> 11977 bytes 2 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 Sample.png diff --git a/Resizable/ViewController.swift b/Resizable/ViewController.swift index ffa0a0c..173b321 100644 --- a/Resizable/ViewController.swift +++ b/Resizable/ViewController.swift @@ -13,8 +13,7 @@ class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let resizableView = ResizableView(frame: CGRect(x: 60, y: 100, width: 200, height: 200)) - resizableView.backgroundColor = UIColor.purple - resizableView.transform = CGAffineTransform(rotationAngle: 0.3) + resizableView.backgroundColor = UIColor.lightGray resizableView.center = CGPoint(x: 160, y: 200) self.view.addSubview(resizableView) } diff --git a/Sample.png b/Sample.png new file mode 100644 index 0000000000000000000000000000000000000000..cb1c2af7ad78085c58fab1f059f5f678661c8cf8 GIT binary patch literal 11977 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 V8umW-*#-hGolDm)=3KB2`5z8>4^aRB literal 0 HcmV?d00001 From 7f4482d44973eb84f5d143088fa6246e11720411 Mon Sep 17 00:00:00 2001 From: Adil Soomro Date: Fri, 24 Feb 2017 23:53:34 +0500 Subject: [PATCH 4/5] Added a screenshot. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b7730c6..f60bec9 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,7 @@ Dragging on the corner handles will resize the view from from the opposite corne Dragging on the rotate handle will adjust the CGAffineTransform rotation value of the view. Dragging on the middle of the view will adjust the view's center position. + + + + From 2ba01f6f58611eaad141bba9a946f9606f105b56 Mon Sep 17 00:00:00 2001 From: Adil Soomro Date: Fri, 3 Nov 2017 16:52:36 +0500 Subject: [PATCH 5/5] Added border to screenshot. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f60bec9..84e0ee9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,6 @@ Dragging on the rotate handle will adjust the CGAffineTransform rotation value o Dragging on the middle of the view will adjust the view's center position. - + - +