From 4859c32289536c3fa161a344d01f4c20b4c250a4 Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Fri, 15 Aug 2014 22:36:26 +0200 Subject: [PATCH 01/15] - updated demo to support transforms - updated SPUserResizableView to support resize with transforms like scale and rotation (when scale is used the distance is calculated with current scale) - added ability to disable panning the view - added to disable resizing - added to disable resizing on more than 1 touch - arc --- SPUserResizableView.xcodeproj/project.pbxproj | 13 +- SPUserResizableView/AppDelegate.m | 7 +- SPUserResizableView/SPUserResizableView.h | 79 ++++++++++-- SPUserResizableView/SPUserResizableView.m | 122 ++++++++++++++++-- SPUserResizableView/ViewController.h | 13 ++ SPUserResizableView/ViewController.m | 67 +++++++++- 6 files changed, 268 insertions(+), 33 deletions(-) diff --git a/SPUserResizableView.xcodeproj/project.pbxproj b/SPUserResizableView.xcodeproj/project.pbxproj index 2d25834..997c184 100644 --- a/SPUserResizableView.xcodeproj/project.pbxproj +++ b/SPUserResizableView.xcodeproj/project.pbxproj @@ -13,9 +13,9 @@ 9C36DD441494491A00D3035F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9C36DD421494491A00D3035F /* InfoPlist.strings */; }; 9C36DD461494491B00D3035F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C36DD451494491B00D3035F /* main.m */; }; 9C36DD4A1494491B00D3035F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C36DD491494491B00D3035F /* AppDelegate.m */; }; - 9C36DD5414944A8F00D3035F /* SPUserResizableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C36DD5114944A8F00D3035F /* SPUserResizableView.m */; }; 9C36DD5514944A8F00D3035F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C36DD5314944A8F00D3035F /* ViewController.m */; }; 9C36DD5714944F1600D3035F /* milky_way.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 9C36DD5614944F1600D3035F /* milky_way.jpg */; }; + B09F23FA199EA6C100A10972 /* SPUserResizableView.m in Sources */ = {isa = PBXBuildFile; fileRef = B09F23F9199EA6C100A10972 /* SPUserResizableView.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,11 +29,11 @@ 9C36DD471494491B00D3035F /* SPUserResizableView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SPUserResizableView-Prefix.pch"; sourceTree = ""; }; 9C36DD481494491B00D3035F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 9C36DD491494491B00D3035F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9C36DD5014944A8F00D3035F /* SPUserResizableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPUserResizableView.h; sourceTree = ""; }; - 9C36DD5114944A8F00D3035F /* SPUserResizableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPUserResizableView.m; sourceTree = ""; }; 9C36DD5214944A8F00D3035F /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 9C36DD5314944A8F00D3035F /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 9C36DD5614944F1600D3035F /* milky_way.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = milky_way.jpg; sourceTree = ""; }; + B09F23F8199EA6C100A10972 /* SPUserResizableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPUserResizableView.h; sourceTree = ""; }; + B09F23F9199EA6C100A10972 /* SPUserResizableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPUserResizableView.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -80,8 +80,8 @@ 9C36DD3F1494491A00D3035F /* SPUserResizableView */ = { isa = PBXGroup; children = ( - 9C36DD5014944A8F00D3035F /* SPUserResizableView.h */, - 9C36DD5114944A8F00D3035F /* SPUserResizableView.m */, + B09F23F8199EA6C100A10972 /* SPUserResizableView.h */, + B09F23F9199EA6C100A10972 /* SPUserResizableView.m */, 9C36DD5214944A8F00D3035F /* ViewController.h */, 9C36DD5314944A8F00D3035F /* ViewController.m */, 9C36DD481494491B00D3035F /* AppDelegate.h */, @@ -168,7 +168,7 @@ files = ( 9C36DD461494491B00D3035F /* main.m in Sources */, 9C36DD4A1494491B00D3035F /* AppDelegate.m in Sources */, - 9C36DD5414944A8F00D3035F /* SPUserResizableView.m in Sources */, + B09F23FA199EA6C100A10972 /* SPUserResizableView.m in Sources */, 9C36DD5514944A8F00D3035F /* ViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -271,6 +271,7 @@ 9C36DD4F1494491B00D3035F /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/SPUserResizableView/AppDelegate.m b/SPUserResizableView/AppDelegate.m index 38162f2..a27d3b0 100644 --- a/SPUserResizableView/AppDelegate.m +++ b/SPUserResizableView/AppDelegate.m @@ -13,17 +13,12 @@ @implementation AppDelegate @synthesize window, viewController; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.viewController = [[ViewController alloc] initWithNibName:nil bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } -- (void)dealloc { - [viewController release]; - [window release]; - [super dealloc]; -} @end diff --git a/SPUserResizableView/SPUserResizableView.h b/SPUserResizableView/SPUserResizableView.h index 9e4ca94..e43e12d 100644 --- a/SPUserResizableView/SPUserResizableView.h +++ b/SPUserResizableView/SPUserResizableView.h @@ -21,7 +21,7 @@ typedef struct SPUserResizableViewAnchorPoint { @interface SPUserResizableView : UIView { SPGripViewBorderView *borderView; - UIView *contentView; + UIView *__weak contentView; CGPoint touchStart; CGFloat minWidth; CGFloat minHeight; @@ -29,34 +29,95 @@ typedef struct SPUserResizableViewAnchorPoint { // Used to determine which components of the bounds we'll be modifying, based upon where the user's touch started. SPUserResizableViewAnchorPoint anchorPoint; - id delegate; + id __weak delegate; + + /** + * This will ensure that when the resizing is done, it will restore + * anchor point. + */ + CGPoint m_originalAnchorPoint; } -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; -// Will be retained as a subview. -@property (nonatomic, assign) UIView *contentView; +/** + * Will be retained as a subview. + */ +@property (nonatomic, weak) UIView *contentView; -// Default is 48.0 for each. +/** + * Minimum width to let user resize + * @default Default is 48.0 for each. + */ @property (nonatomic) CGFloat minWidth; +/** + * Minimum height that will let user to resize + */ @property (nonatomic) CGFloat minHeight; -// Defaults to YES. Disables the user from dragging the view outside the parent view's bounds. +/** + * Disables resize of the view + * @default NO + */ +@property (nonatomic) BOOL disable; + +/** + * Disables resize of the view if user use more than 1 finger. + * @default NO + */ +@property (nonatomic) BOOL disableOnMultiTouch; +/** + * Defaults to YES. Disables the user from dragging the view outside the parent view's bounds. + */ @property (nonatomic) BOOL preventsPositionOutsideSuperview; +/** + * Defines if pan is disabled. + * @default NO + */ +@property (nonatomic) BOOL disablePan; + +/** + * Hide editing handles + */ - (void)hideEditingHandles; +/** + * Shows editing handles + */ - (void)showEditingHandles; +/** + * Is currently resizing? + * + * @return BOOL + */ +- (BOOL)isResizing; + @end @protocol SPUserResizableViewDelegate @optional -// Called when the resizable view receives touchesBegan: and activates the editing handles. +/** + * Called when the resizable view receives touchesBegan: and activates the editing handles. + * + * @param userResizableView + */ - (void)userResizableViewDidBeginEditing:(SPUserResizableView *)userResizableView; -// Called when the resizable view receives touchesEnded: or touchesCancelled: +/** + * Called when the resizable view receives touchesEnded: or touchesCancelled: + * + * @param userResizableView + */ - (void)userResizableViewDidEndEditing:(SPUserResizableView *)userResizableView; +/** + * Called when new frame was set. + * + * @param userResizableView + */ +- (void)userResizableViewNewRealFrame:(SPUserResizableView *)userResizableView;; + @end diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index c2681a7..490e0d6 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -92,6 +92,30 @@ - (void)drawRect:(CGRect)rect { @end +@interface SPUserResizableView () + +- (void)translateUsingTouchLocation:(CGPoint)touchPoint; + +/** + * Used for moving anchorPoint without loosing current position. Works with transform + * @author http://stackoverflow.com/a/5666430/740949 + * + * @param anchor CGPoint for new anchor + * @param view + */ +-(void)setAnchorPoint:(CGPoint)anchor; + +/** + * Determines if we should not resize the by current settings. + * + * @param touches + * + * @return BOOL + */ +- (BOOL)isDisabledForTouches:(NSSet*)touches; + +@end + @implementation SPUserResizableView @synthesize contentView, minWidth, minHeight, preventsPositionOutsideSuperview, delegate; @@ -177,7 +201,18 @@ - (BOOL)isResizing { return (anchorPoint.adjustsH || anchorPoint.adjustsW || anchorPoint.adjustsX || anchorPoint.adjustsY); } +- (BOOL)isDisabledForTouches:(NSSet*)touches { + return ([self disable] || ([self disableOnMultiTouch] && [touches count] > 1)); +} + + - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + if ([self isDisabledForTouches:touches]) { + return; + } + + m_originalAnchorPoint = [[self layer] anchorPoint]; + // Notify the delegate we've begun our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidBeginEditing:)]) { [self.delegate userResizableViewDidBeginEditing:self]; @@ -196,6 +231,9 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + + [self setAnchorPoint:m_originalAnchorPoint]; + // Notify the delegate we've ended our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { [self.delegate userResizableViewDidEndEditing:self]; @@ -203,6 +241,9 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + + [self setAnchorPoint:m_originalAnchorPoint]; + // Notify the delegate we've ended our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { [self.delegate userResizableViewDidEndEditing:self]; @@ -218,7 +259,37 @@ - (void)hideEditingHandles { } - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { + if ([self disable]) { + return; + } + + // save current rotation and scales + CGFloat scaleX = [[self valueForKeyPath:@"layer.transform.scale.x"] floatValue]; + CGFloat scaleY = [[self valueForKeyPath:@"layer.transform.scale.y"] floatValue]; + CGFloat rotation = [[self valueForKeyPath:@"layer.transform.rotation"] floatValue]; + + // update current anchor point to update frane with transform + + CGPoint point; + if (anchorPoint.adjustsY != 0) { + if (anchorPoint.adjustsW != 0 && anchorPoint.adjustsX == 0) { + point = CGPointMake(0, 1); + } else { + point = CGPointMake(1, 1); + } + } else if (anchorPoint.adjustsX != 0) { + point = CGPointMake(1, 0); + } else { + point = CGPointMake(0, 0); + } + + [self setAnchorPoint:point]; + + // restore to normal cords + [self setTransform:CGAffineTransformIdentity]; + // (1) Update the touch point if we're outside the superview. + if (self.preventsPositionOutsideSuperview) { CGFloat border = kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2; if (touchPoint.x < border) { @@ -236,9 +307,9 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { } // (2) Calculate the deltas using the current anchor point. - CGFloat deltaW = anchorPoint.adjustsW * (touchStart.x - touchPoint.x); + CGFloat deltaW = anchorPoint.adjustsW * (touchStart.x - touchPoint.x) / scaleX; CGFloat deltaX = anchorPoint.adjustsX * (-1.0 * deltaW); - CGFloat deltaH = anchorPoint.adjustsH * (touchPoint.y - touchStart.y); + CGFloat deltaH = anchorPoint.adjustsH * (touchPoint.y - touchStart.y) / scaleY; CGFloat deltaY = anchorPoint.adjustsY * (-1.0 * deltaH); // (3) Calculate the new frame. @@ -279,11 +350,24 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { } } + // update the frame self.frame = CGRectMake(newX, newY, newWidth, newHeight); + + if ([self delegate] && [[self delegate] respondsToSelector:@selector(userResizableViewNewRealFrame:)]) { + [[self delegate] userResizableViewNewRealFrame:self]; + } + + // resotre the transform + CGAffineTransform transform = CGAffineTransformMakeRotation(rotation); + + [self setTransform:CGAffineTransformScale(transform, scaleX, scaleY)]; + + touchStart = touchPoint; } - (void)translateUsingTouchLocation:(CGPoint)touchPoint { + [self setAnchorPoint:CGPointMake(0.5, 0.5)]; CGPoint newCenter = CGPointMake(self.center.x + touchPoint.x - touchStart.x, self.center.y + touchPoint.y - touchStart.y); if (self.preventsPositionOutsideSuperview) { // Ensure the translation won't cause the view to move offscreen. @@ -305,18 +389,40 @@ - (void)translateUsingTouchLocation:(CGPoint)touchPoint { self.center = newCenter; } +-(void)setAnchorPoint:(CGPoint)anchor { + CGPoint newPoint = CGPointMake(self.bounds.size.width * anchor.x, + self.bounds.size.height * anchor.y); + CGPoint oldPoint = CGPointMake(self.bounds.size.width * self.layer.anchorPoint.x, + self.bounds.size.height * self.layer.anchorPoint.y); + + newPoint = CGPointApplyAffineTransform(newPoint, self.transform); + oldPoint = CGPointApplyAffineTransform(oldPoint, self.transform); + + CGPoint position = self.layer.position; + + position.x -= oldPoint.x; + position.x += newPoint.x; + + position.y -= oldPoint.y; + position.y += newPoint.y; + + self.layer.position = position; + self.layer.anchorPoint = anchor; +} + - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - if ([self isResizing]) { - [self resizeUsingTouchLocation:[[touches anyObject] locationInView:self.superview]]; - } else { - [self translateUsingTouchLocation:[[touches anyObject] locationInView:self]]; + // is disabled or there are more touches + if (![self isDisabledForTouches:touches]) { + if ([self isResizing]) { + [self resizeUsingTouchLocation:[[touches anyObject] locationInView:self.superview]]; + } else if (![self disablePan]){ + [self translateUsingTouchLocation:[[touches anyObject] locationInView:self]]; + } } } - (void)dealloc { [contentView removeFromSuperview]; - [borderView release]; - [super dealloc]; } @end diff --git a/SPUserResizableView/ViewController.h b/SPUserResizableView/ViewController.h index 7ba5829..5d03df1 100644 --- a/SPUserResizableView/ViewController.h +++ b/SPUserResizableView/ViewController.h @@ -11,6 +11,19 @@ @interface ViewController : UIViewController { SPUserResizableView *currentlyEditingView; SPUserResizableView *lastEditedView; + + /** + * Pinch lastScale + */ + CGFloat lastScale; + + /** + * Rotate lastRotation + */ + CGFloat lastRotation; } +- (void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer; +- (void)handleRotateGesture:(UIRotationGestureRecognizer*)sender; + @end diff --git a/SPUserResizableView/ViewController.m b/SPUserResizableView/ViewController.m index 2bbe3c2..2d8e9bf 100644 --- a/SPUserResizableView/ViewController.m +++ b/SPUserResizableView/ViewController.m @@ -25,7 +25,6 @@ - (void)viewDidLoad { currentlyEditingView = userResizableView; lastEditedView = userResizableView; [self.view addSubview:userResizableView]; - [contentView release]; [userResizableView release]; // (2) Create a second resizable view with a UIImageView as the content. CGRect imageFrame = CGRectMake(50, 200, 200, 200); @@ -33,13 +32,25 @@ - (void)viewDidLoad { UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"milky_way.jpg"]]; imageResizableView.contentView = imageView; imageResizableView.delegate = self; + + [imageResizableView setTransform:CGAffineTransformMakeRotation(0.1)]; + [self.view addSubview:imageResizableView]; - [imageView release]; [imageResizableView release]; UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideEditingHandles)]; [gestureRecognizer setDelegate:self]; [self.view addGestureRecognizer:gestureRecognizer]; - [gestureRecognizer release]; + + UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; + [pinchRecognizer setDelegate:self]; + [userResizableView addGestureRecognizer:pinchRecognizer]; + [imageResizableView addGestureRecognizer:pinchRecognizer]; + + UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotateGesture:)]; + [rotationRecognizer setDelegate:self]; + + [userResizableView addGestureRecognizer:rotationRecognizer]; + [imageResizableView addGestureRecognizer:rotationRecognizer]; } - (void)userResizableViewDidBeginEditing:(SPUserResizableView *)userResizableView { @@ -52,16 +63,64 @@ - (void)userResizableViewDidEndEditing:(SPUserResizableView *)userResizableView } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { if ([currentlyEditingView hitTest:[touch locationInView:currentlyEditingView] withEvent:nil]) { return NO; } + } + return YES; +} +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } - - (void)hideEditingHandles { // We only want the gesture recognizer to end the editing session on the last // edited view. We wouldn't want to dismiss an editing session in progress. [lastEditedView hideEditingHandles]; } +- (void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer { + + if([gestureRecognizer state] == UIGestureRecognizerStateBegan) { + // Reset the last scale, necessary if there are multiple objects with different scales + lastScale = [gestureRecognizer scale]; + } + + if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || + [gestureRecognizer state] == UIGestureRecognizerStateChanged) { + + CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:@"transform.scale"] floatValue]; + + // Constants to adjust the max/min values of zoom + const CGFloat kMaxScale = 2.0; + const CGFloat kMinScale = 1.0; + + CGFloat newScale = 1 - (lastScale - [gestureRecognizer scale]); + newScale = MIN(newScale, kMaxScale / currentScale); + newScale = MAX(newScale, kMinScale / currentScale); + CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale); + [gestureRecognizer view].transform = transform; + + lastScale = [gestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call + } +} + +-(void)handleRotateGesture:(UIRotationGestureRecognizer*)sender { + + if([(UIRotationGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) { + + lastRotation = 0.0; + return; + } + + CGFloat rotation = 0.0 - (lastRotation - [sender rotation]); + + CGAffineTransform currentTransform = [sender view] .transform; + CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform,rotation); + + [[sender view] setTransform:newTransform]; + + lastRotation = [(UIRotationGestureRecognizer*)sender rotation]; +} + @end From d23bfc81959015036c80f1c5007f0a382e12e692 Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Fri, 24 Oct 2014 11:12:55 +0200 Subject: [PATCH 02/15] - fixed resize after rotation in -radians (need to fix dragging by corners) --- SPUserResizableView.xcodeproj/project.pbxproj | 2 + SPUserResizableView/SPUserResizableView.m | 63 +++++++++++++++--- SPUserResizableView/ViewController.m | 3 +- SPUserResizableView/milky_way.jpg | Bin 13551 -> 17135 bytes 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/SPUserResizableView.xcodeproj/project.pbxproj b/SPUserResizableView.xcodeproj/project.pbxproj index 997c184..c6d2f33 100644 --- a/SPUserResizableView.xcodeproj/project.pbxproj +++ b/SPUserResizableView.xcodeproj/project.pbxproj @@ -237,6 +237,7 @@ GCC_PREFIX_HEADER = "SPUserResizableView/SPUserResizableView-Prefix.pch"; INFOPLIST_FILE = "SPUserResizableView/SPUserResizableView-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -248,6 +249,7 @@ GCC_PREFIX_HEADER = "SPUserResizableView/SPUserResizableView-Prefix.pch"; INFOPLIST_FILE = "SPUserResizableView/SPUserResizableView-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 490e0d6..4decef3 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -6,6 +6,7 @@ // #import "SPUserResizableView.h" +#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI)) /* Let's inset everything that's drawn (the handles and the content view) so that users can trigger a resize from a few pixels outside of @@ -173,6 +174,8 @@ static CGFloat SPDistanceBetweenTwoPoints(CGPoint point1, CGPoint point2) { } CGPointSPUserResizableViewAnchorPointPair; - (SPUserResizableViewAnchorPoint)anchorPointForTouchLocation:(CGPoint)touchPoint { + + // (1) Calculate the positions of each of the anchor points. CGPointSPUserResizableViewAnchorPointPair upperLeft = { CGPointMake(0.0, 0.0), SPUserResizableViewUpperLeftAnchorPoint }; CGPointSPUserResizableViewAnchorPointPair upperMiddle = { CGPointMake(self.bounds.size.width/2, 0.0), SPUserResizableViewUpperMiddleAnchorPoint }; @@ -220,6 +223,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [borderView setHidden:NO]; UITouch *touch = [touches anyObject]; + anchorPoint = [self anchorPointForTouchLocation:[touch locationInView:self]]; // When resizing, all calculations are done in the superview's coordinate space. @@ -263,6 +267,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { return; } + NSLog(@"Touch point %@",NSStringFromCGPoint(touchPoint)); // save current rotation and scales CGFloat scaleX = [[self valueForKeyPath:@"layer.transform.scale.x"] floatValue]; CGFloat scaleY = [[self valueForKeyPath:@"layer.transform.scale.y"] floatValue]; @@ -270,7 +275,14 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { // update current anchor point to update frane with transform + //NSLog(@"H %f, W %f, X %f, Y %f", anchorPoint.adjustsH, anchorPoint.adjustsW, anchorPoint.adjustsX, anchorPoint.adjustsY); + + + NSLog(@"Rotation %f",RADIANS_TO_DEGREES(rotation)); + + CGPoint point; + if (anchorPoint.adjustsY != 0) { if (anchorPoint.adjustsW != 0 && anchorPoint.adjustsX == 0) { point = CGPointMake(0, 1); @@ -283,6 +295,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { point = CGPointMake(0, 0); } + [self setAnchorPoint:point]; // restore to normal cords @@ -307,29 +320,58 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { } // (2) Calculate the deltas using the current anchor point. - CGFloat deltaW = anchorPoint.adjustsW * (touchStart.x - touchPoint.x) / scaleX; + + CGPoint start = touchStart; + CGPoint end = touchPoint; + + float rotationDeg = RADIANS_TO_DEGREES(rotation); + + if (rotationDeg > 45.0 && rotationDeg < 135.0) { + + start.x = touchStart.y; + start.y = touchPoint.x; + + end.x = touchPoint.y; + end.y = touchStart.x; + } else if (-45.0 > rotationDeg && rotationDeg > -135.0) { + start.x = touchPoint.y; + start.y = touchStart.x; + + end.x = touchStart.y; + end.y = touchPoint.x; + //} else if (-135.0 > rotationDeg) { + + } else if (rotationDeg > 135.0 || -135.0 > rotationDeg) { + start = touchPoint; + end = touchStart; + } + + + + CGFloat deltaW = anchorPoint.adjustsW * (start.x - end.x) / scaleX; CGFloat deltaX = anchorPoint.adjustsX * (-1.0 * deltaW); - CGFloat deltaH = anchorPoint.adjustsH * (touchPoint.y - touchStart.y) / scaleY; + CGFloat deltaH = anchorPoint.adjustsH * (end.y - start.y) / scaleY; CGFloat deltaY = anchorPoint.adjustsY * (-1.0 * deltaH); // (3) Calculate the new frame. CGFloat newX = self.frame.origin.x + deltaX; CGFloat newY = self.frame.origin.y + deltaY; - CGFloat newWidth = self.frame.size.width + deltaW; - CGFloat newHeight = self.frame.size.height + deltaH; + CGFloat newWidth = self.bounds.size.width + deltaW; + CGFloat newHeight = self.bounds.size.height + deltaH; // (4) If the new frame is too small, cancel the changes. if (newWidth < self.minWidth) { - newWidth = self.frame.size.width; + newWidth = self.bounds.size.width; newX = self.frame.origin.x; } if (newHeight < self.minHeight) { - newHeight = self.frame.size.height; + newHeight = self.bounds.size.height; newY = self.frame.origin.y; } // (5) Ensure the resize won't cause the view to move offscreen. if (self.preventsPositionOutsideSuperview) { + /* if (newX < self.superview.bounds.origin.x) { // Calculate how much to grow the width by such that the new X coordintae will align with the superview. deltaW = self.frame.origin.x - self.superview.bounds.origin.x; @@ -341,13 +383,13 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { } if (newY < self.superview.bounds.origin.y) { // Calculate how much to grow the height by such that the new Y coordintae will align with the superview. - deltaH = self.frame.origin.y - self.superview.bounds.origin.y; + deltaH = self.bounds.origin.y - self.superview.bounds.origin.y; newHeight = self.frame.size.height + deltaH; newY = self.superview.bounds.origin.y; } if (newY + newHeight > self.superview.bounds.origin.y + self.superview.bounds.size.height) { newHeight = self.superview.bounds.size.height - newY; - } + }*/ } // update the frame @@ -356,19 +398,20 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { if ([self delegate] && [[self delegate] respondsToSelector:@selector(userResizableViewNewRealFrame:)]) { [[self delegate] userResizableViewNewRealFrame:self]; } - // resotre the transform CGAffineTransform transform = CGAffineTransformMakeRotation(rotation); [self setTransform:CGAffineTransformScale(transform, scaleX, scaleY)]; - + touchStart = touchPoint; } - (void)translateUsingTouchLocation:(CGPoint)touchPoint { [self setAnchorPoint:CGPointMake(0.5, 0.5)]; + CGPoint newCenter = CGPointMake(self.center.x + touchPoint.x - touchStart.x, self.center.y + touchPoint.y - touchStart.y); + if (self.preventsPositionOutsideSuperview) { // Ensure the translation won't cause the view to move offscreen. CGFloat midPointX = CGRectGetMidX(self.bounds); diff --git a/SPUserResizableView/ViewController.m b/SPUserResizableView/ViewController.m index 2d8e9bf..acf774b 100644 --- a/SPUserResizableView/ViewController.m +++ b/SPUserResizableView/ViewController.m @@ -27,11 +27,12 @@ - (void)viewDidLoad { [self.view addSubview:userResizableView]; // (2) Create a second resizable view with a UIImageView as the content. - CGRect imageFrame = CGRectMake(50, 200, 200, 200); + CGRect imageFrame = CGRectMake(200, 200, 200, 200); SPUserResizableView *imageResizableView = [[SPUserResizableView alloc] initWithFrame:imageFrame]; UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"milky_way.jpg"]]; imageResizableView.contentView = imageView; imageResizableView.delegate = self; + imageResizableView.disablePan = YES; [imageResizableView setTransform:CGAffineTransformMakeRotation(0.1)]; diff --git a/SPUserResizableView/milky_way.jpg b/SPUserResizableView/milky_way.jpg index 83f0a8dfda1d77fc498a60517f6071966e94861d..2089c6205ec6472fd5bb7e0b4b92d570070cd16e 100644 GIT binary patch delta 13942 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

t!o?)`6+E3yfj3`OJ0|=)gA) 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 EA0`X(3;+NC delta 10331 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 G%l{9Hl6Bbt From c50bfcf21e521a1752f4de4d11243ac2d0ac472c Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Fri, 24 Oct 2014 11:31:39 +0200 Subject: [PATCH 03/15] Addpod spec --- SPUserResizableView.podspec | 17 ++++++++ .../contents.xcworkspacedata | 7 +++ .../SPUserResizableView.xccheckout | 41 ++++++++++++++++++ .../UserInterfaceState.xcuserstate | Bin 0 -> 14066 bytes 4 files changed, 65 insertions(+) create mode 100644 SPUserResizableView.podspec create mode 100644 SPUserResizableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 SPUserResizableView.xcodeproj/project.xcworkspace/xcshareddata/SPUserResizableView.xccheckout create mode 100644 SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/SPUserResizableView.podspec b/SPUserResizableView.podspec new file mode 100644 index 0000000..11bcd4d --- /dev/null +++ b/SPUserResizableView.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |s| + s.name = 'SPUserResizableView+Pion' + s.version = '0.5' + s.license = 'MIT' + s.homepage = 'https://github.com/pionl/SPUserResizableView' + s.authors = 'Stephen Poletto' + s.summary = 'A forked (originaly from STephen Poletto) SPUserResizableView is a user-resizable, user-repositionable UIView subclass. It is modeled after the resizable image view from the Pages iOS app. ' + +# Source Info + s.platform = :ios, '5.0' + s.source = {:git => 'https://github.com/pionl/SPUserResizableView', :tag => '0.5'} + s.source_files = 'SPUserResizableView.{h,m}' + s.requires_arc = true + +# Pod Dependencies + +end \ No newline at end of file diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SPUserResizableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..bb8938a --- /dev/null +++ b/SPUserResizableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcshareddata/SPUserResizableView.xccheckout b/SPUserResizableView.xcodeproj/project.xcworkspace/xcshareddata/SPUserResizableView.xccheckout new file mode 100644 index 0000000..612dd6c --- /dev/null +++ b/SPUserResizableView.xcodeproj/project.xcworkspace/xcshareddata/SPUserResizableView.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + FEFFC6DF-8462-42E6-AAA1-3BD8896B7261 + IDESourceControlProjectName + SPUserResizableView + IDESourceControlProjectOriginsDictionary + + 4519E06DE028306E8037FDB194956AEBC0491ED8 + https://github.com/pionl/SPUserResizableView.git + + IDESourceControlProjectPath + SPUserResizableView.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + 4519E06DE028306E8037FDB194956AEBC0491ED8 + ../.. + + IDESourceControlProjectURL + https://github.com/pionl/SPUserResizableView.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 4519E06DE028306E8037FDB194956AEBC0491ED8 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 4519E06DE028306E8037FDB194956AEBC0491ED8 + IDESourceControlWCCName + SPUserResizableView + + + + diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate b/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..84cea247289a013f305758bebc5f5e5cab83d9b2 GIT binary patch literal 14066 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 literal 0 HcmV?d00001 From 5673e1bf45a72a68d79c4701afb87ac14dbae902 Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Fri, 24 Oct 2014 13:08:03 +0200 Subject: [PATCH 04/15] added option to setup border size and contentInset for better detection --- SPUserResizableView.podspec | 17 ---- .../UserInterfaceState.xcuserstate | Bin 14066 -> 17266 bytes SPUserResizableView/SPUserResizableView.h | 20 +++++ SPUserResizableView/SPUserResizableView.m | 82 +++++++++++++----- SPUserResizableView/ViewController.m | 7 ++ 5 files changed, 85 insertions(+), 41 deletions(-) delete mode 100644 SPUserResizableView.podspec diff --git a/SPUserResizableView.podspec b/SPUserResizableView.podspec deleted file mode 100644 index 11bcd4d..0000000 --- a/SPUserResizableView.podspec +++ /dev/null @@ -1,17 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'SPUserResizableView+Pion' - s.version = '0.5' - s.license = 'MIT' - s.homepage = 'https://github.com/pionl/SPUserResizableView' - s.authors = 'Stephen Poletto' - s.summary = 'A forked (originaly from STephen Poletto) SPUserResizableView is a user-resizable, user-repositionable UIView subclass. It is modeled after the resizable image view from the Pages iOS app. ' - -# Source Info - s.platform = :ios, '5.0' - s.source = {:git => 'https://github.com/pionl/SPUserResizableView', :tag => '0.5'} - s.source_files = 'SPUserResizableView.{h,m}' - s.requires_arc = true - -# Pod Dependencies - -end \ No newline at end of file diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate b/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate index 84cea247289a013f305758bebc5f5e5cab83d9b2..76d932acd590f896e93af11119dc9c0caf456ecb 100644 GIT binary patch delta 10250 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 diff --git a/SPUserResizableView/SPUserResizableView.h b/SPUserResizableView/SPUserResizableView.h index e43e12d..9357dc7 100644 --- a/SPUserResizableView/SPUserResizableView.h +++ b/SPUserResizableView/SPUserResizableView.h @@ -9,6 +9,15 @@ #import +/* Let's inset everything that's drawn (the handles and the content view) + so that users can trigger a resize from a few pixels outside of + what they actually see as the bounding box. */ +#define kSPUserResizableViewGlobalInset 5.0 + +#define kSPUserResizableViewDefaultMinWidth 48.0 +#define kSPUserResizableViewDefaultMinHeight 48.0 +#define kSPUserResizableViewInteractiveBorderSize 10.0 + typedef struct SPUserResizableViewAnchorPoint { CGFloat adjustsX; CGFloat adjustsY; @@ -36,6 +45,7 @@ typedef struct SPUserResizableViewAnchorPoint { * anchor point. */ CGPoint m_originalAnchorPoint; + } @property (nonatomic, weak) id delegate; @@ -77,6 +87,16 @@ typedef struct SPUserResizableViewAnchorPoint { */ @property (nonatomic) BOOL disablePan; +/** + * Defines the insent of the content. + * Larger == better detection + */ +@property (nonatomic) float resizableInset; +/** + * Interactive border size + */ +@property (nonatomic) float interactiveBorderSize; + /** * Hide editing handles */ diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 4decef3..0b7df3c 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -8,15 +8,6 @@ #import "SPUserResizableView.h" #define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI)) -/* Let's inset everything that's drawn (the handles and the content view) - so that users can trigger a resize from a few pixels outside of - what they actually see as the bounding box. */ -#define kSPUserResizableViewGlobalInset 5.0 - -#define kSPUserResizableViewDefaultMinWidth 48.0 -#define kSPUserResizableViewDefaultMinHeight 48.0 -#define kSPUserResizableViewInteractiveBorderSize 10.0 - static SPUserResizableViewAnchorPoint SPUserResizableViewNoResizeAnchorPoint = { 0.0, 0.0, 0.0, 0.0 }; static SPUserResizableViewAnchorPoint SPUserResizableViewUpperLeftAnchorPoint = { 1.0, 1.0, -1.0, 1.0 }; static SPUserResizableViewAnchorPoint SPUserResizableViewMiddleLeftAnchorPoint = { 1.0, 0.0, 0.0, 1.0 }; @@ -28,6 +19,10 @@ static SPUserResizableViewAnchorPoint SPUserResizableViewLowerMiddleAnchorPoint = { 0.0, 0.0, 1.0, 0.0 }; @interface SPGripViewBorderView : UIView + +@property (nonatomic) float resizableInset; +@property (nonatomic) float interactiveBorderSize; + @end @implementation SPGripViewBorderView @@ -47,18 +42,18 @@ - (void)drawRect:(CGRect)rect { // (1) Draw the bounding box. CGContextSetLineWidth(context, 1.0); CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor); - CGContextAddRect(context, CGRectInset(self.bounds, kSPUserResizableViewInteractiveBorderSize/2, kSPUserResizableViewInteractiveBorderSize/2)); + CGContextAddRect(context, CGRectInset(self.bounds, [self interactiveBorderSize]/2, [self interactiveBorderSize]/2)); CGContextStrokePath(context); // (2) Calculate the bounding boxes for each of the anchor points. - CGRect upperLeft = CGRectMake(0.0, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect upperRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect lowerRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect lowerLeft = CGRectMake(0.0, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect upperMiddle = CGRectMake((self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize)/2, 0.0, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect lowerMiddle = CGRectMake((self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize)/2, self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect middleLeft = CGRectMake(0.0, (self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize)/2, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); - CGRect middleRight = CGRectMake(self.bounds.size.width - kSPUserResizableViewInteractiveBorderSize, (self.bounds.size.height - kSPUserResizableViewInteractiveBorderSize)/2, kSPUserResizableViewInteractiveBorderSize, kSPUserResizableViewInteractiveBorderSize); + CGRect upperLeft = CGRectMake(0.0, 0.0, [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect upperRight = CGRectMake(self.bounds.size.width - [self interactiveBorderSize], 0.0, [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect lowerRight = CGRectMake(self.bounds.size.width - [self interactiveBorderSize], self.bounds.size.height - [self interactiveBorderSize], [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect lowerLeft = CGRectMake(0.0, self.bounds.size.height - [self interactiveBorderSize], [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect upperMiddle = CGRectMake((self.bounds.size.width - [self interactiveBorderSize])/2, 0.0, [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect lowerMiddle = CGRectMake((self.bounds.size.width - [self interactiveBorderSize])/2, self.bounds.size.height - [self interactiveBorderSize], [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect middleLeft = CGRectMake(0.0, (self.bounds.size.height - [self interactiveBorderSize])/2, [self interactiveBorderSize], [self interactiveBorderSize]); + CGRect middleRight = CGRectMake(self.bounds.size.width - [self interactiveBorderSize], (self.bounds.size.height - [self interactiveBorderSize])/2, [self interactiveBorderSize], [self interactiveBorderSize]); // (3) Create the gradient to paint the anchor points. CGFloat colors [] = { @@ -121,13 +116,25 @@ @implementation SPUserResizableView @synthesize contentView, minWidth, minHeight, preventsPositionOutsideSuperview, delegate; + - (void)setupDefaultAttributes { - borderView = [[SPGripViewBorderView alloc] initWithFrame:CGRectInset(self.bounds, kSPUserResizableViewGlobalInset, kSPUserResizableViewGlobalInset)]; + + // craete border view + borderView = [[SPGripViewBorderView alloc] initWithFrame:CGRectInset(self.bounds, [self resizableInset], [self resizableInset])]; [borderView setHidden:YES]; + [self addSubview:borderView]; + + // setup self.minWidth = kSPUserResizableViewDefaultMinWidth; self.minHeight = kSPUserResizableViewDefaultMinHeight; self.preventsPositionOutsideSuperview = YES; + + _disable = NO; + + [self setResizableInset:kSPUserResizableViewGlobalInset]; + [self setInteractiveBorderSize:kSPUserResizableViewInteractiveBorderSize]; + } - (id)initWithFrame:(CGRect)frame { @@ -144,10 +151,27 @@ - (id)initWithCoder:(NSCoder *)aDecoder { return self; } +// we need to update also border view +- (void)setResizableInset:(float)resizableInset { + _resizableInset = resizableInset; + [borderView setResizableInset:resizableInset]; + + [self setFrame:[self frame]]; +} + +- (void)setInteractiveBorderSize:(float)interactiveBorderSize { + _interactiveBorderSize = interactiveBorderSize; + [borderView setInteractiveBorderSize:interactiveBorderSize]; + + [self setFrame:[self frame]]; +} + - (void)setContentView:(UIView *)newContentView { [contentView removeFromSuperview]; contentView = newContentView; - contentView.frame = CGRectInset(self.bounds, kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2, kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2); + + contentView.frame = CGRectInset(self.bounds, [self resizableInset] + [self interactiveBorderSize]/2, [self resizableInset] + [self interactiveBorderSize]/2); + [self addSubview:contentView]; // Ensure the border view is always on top by removing it and adding it to the end of the subview list. @@ -157,8 +181,9 @@ - (void)setContentView:(UIView *)newContentView { - (void)setFrame:(CGRect)newFrame { [super setFrame:newFrame]; - contentView.frame = CGRectInset(self.bounds, kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2, kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2); - borderView.frame = CGRectInset(self.bounds, kSPUserResizableViewGlobalInset, kSPUserResizableViewGlobalInset); + + contentView.frame = CGRectInset(self.bounds, [self resizableInset] + [self interactiveBorderSize]/2, [self resizableInset] + [self interactiveBorderSize]/2); + borderView.frame = CGRectInset(self.bounds, [self resizableInset], [self resizableInset]); [borderView setNeedsDisplay]; } @@ -197,7 +222,16 @@ - (SPUserResizableViewAnchorPoint)anchorPointForTouchLocation:(CGPoint)touchPoin smallestDistance = distance; } } - return closestPoint.anchorPoint; + + + // make dragable only small portion of border. + float check = ([self resizableInset]+5) * 2; + + if (touchPoint.x < check+[self resizableInset] || touchPoint.x >= (self.bounds.size.width-check) || touchPoint.y < check+[self resizableInset] || touchPoint.y >= (self.bounds.size.height-check)) { + return closestPoint.anchorPoint; + } else { + return (SPUserResizableViewAnchorPoint){0,0,0,0}; + } } - (BOOL)isResizing { @@ -304,7 +338,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { // (1) Update the touch point if we're outside the superview. if (self.preventsPositionOutsideSuperview) { - CGFloat border = kSPUserResizableViewGlobalInset + kSPUserResizableViewInteractiveBorderSize/2; + CGFloat border = [self resizableInset] + [self interactiveBorderSize]/2; if (touchPoint.x < border) { touchPoint.x = border; } diff --git a/SPUserResizableView/ViewController.m b/SPUserResizableView/ViewController.m index acf774b..e1968ea 100644 --- a/SPUserResizableView/ViewController.m +++ b/SPUserResizableView/ViewController.m @@ -29,7 +29,14 @@ - (void)viewDidLoad { // (2) Create a second resizable view with a UIImageView as the content. CGRect imageFrame = CGRectMake(200, 200, 200, 200); SPUserResizableView *imageResizableView = [[SPUserResizableView alloc] initWithFrame:imageFrame]; + UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"milky_way.jpg"]]; + + [imageResizableView setInteractiveBorderSize:12.0]; + [imageResizableView setMinWidth:140.0]; + [imageResizableView setMinHeight:120.0]; + [imageResizableView setResizableInset:30]; + imageResizableView.contentView = imageView; imageResizableView.delegate = self; imageResizableView.disablePan = YES; From ea6c2b0de6b22a18a03ca41a8777613a9139043d Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Mon, 27 Oct 2014 16:27:41 +0100 Subject: [PATCH 05/15] - improved detection when resize can be applied for better gesture handling. --- .../UserInterfaceState.xcuserstate | Bin 17266 -> 19755 bytes SPUserResizableView/SPUserResizableView.m | 94 +++++++++++------- SPUserResizableView/ViewController.m | 2 +- 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate b/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate index 76d932acd590f896e93af11119dc9c0caf456ecb..c3964a21f0927fddc8c4284c1cab9afac57588e7 100644 GIT binary patch literal 19755 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 T?mnC2PhE0BrpTa1oOaruoNr< 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 diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 0b7df3c..ad03983 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -56,8 +56,8 @@ - (void)drawRect:(CGRect)rect { CGRect middleRight = CGRectMake(self.bounds.size.width - [self interactiveBorderSize], (self.bounds.size.height - [self interactiveBorderSize])/2, [self interactiveBorderSize], [self interactiveBorderSize]); // (3) Create the gradient to paint the anchor points. - CGFloat colors [] = { - 0.4, 0.8, 1.0, 1.0, + CGFloat colors [] = { + 0.4, 0.8, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0 }; CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); @@ -110,6 +110,13 @@ -(void)setAnchorPoint:(CGPoint)anchor; */ - (BOOL)isDisabledForTouches:(NSSet*)touches; +/** + * Checks if user did change the view + * + * @return BOOL + */ +- (BOOL)willResize:(CGPoint)point; + @end @implementation SPUserResizableView @@ -182,9 +189,11 @@ - (void)setContentView:(UIView *)newContentView { - (void)setFrame:(CGRect)newFrame { [super setFrame:newFrame]; - contentView.frame = CGRectInset(self.bounds, [self resizableInset] + [self interactiveBorderSize]/2, [self resizableInset] + [self interactiveBorderSize]/2); - borderView.frame = CGRectInset(self.bounds, [self resizableInset], [self resizableInset]); - [borderView setNeedsDisplay]; + if (contentView) { + contentView.frame = CGRectInset(self.bounds, [self resizableInset] + [self interactiveBorderSize]/2, [self resizableInset] + [self interactiveBorderSize]/2); + borderView.frame = CGRectInset(self.bounds, [self resizableInset], [self resizableInset]); + [borderView setNeedsDisplay]; + } } static CGFloat SPDistanceBetweenTwoPoints(CGPoint point1, CGPoint point2) { @@ -217,7 +226,7 @@ - (SPUserResizableViewAnchorPoint)anchorPointForTouchLocation:(CGPoint)touchPoin CGFloat smallestDistance = MAXFLOAT; CGPointSPUserResizableViewAnchorPointPair closestPoint = centerPoint; for (NSInteger i = 0; i < 9; i++) { CGFloat distance = SPDistanceBetweenTwoPoints(touchPoint, allPoints[i].point); - if (distance < smallestDistance) { + if (distance < smallestDistance) { closestPoint = allPoints[i]; smallestDistance = distance; } @@ -242,13 +251,17 @@ - (BOOL)isDisabledForTouches:(NSSet*)touches { return ([self disable] || ([self disableOnMultiTouch] && [touches count] > 1)); } +- (BOOL)willResize:(CGPoint)point { + // dermine if we will make resize + return [self isResizing] && (point.x != touchStart.x && point.y != touchStart.y); +} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if ([self isDisabledForTouches:touches]) { return; } - m_originalAnchorPoint = [[self layer] anchorPoint]; + //m_originalAnchorPoint = [[self layer] anchorPoint]; // Notify the delegate we've begun our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidBeginEditing:)]) { @@ -269,8 +282,10 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - - [self setAnchorPoint:m_originalAnchorPoint]; + if ([self isDisabledForTouches:touches]) { + return; + } + //[self setAnchorPoint:m_originalAnchorPoint]; // Notify the delegate we've ended our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { @@ -279,8 +294,11 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - - [self setAnchorPoint:m_originalAnchorPoint]; + if ([self isDisabledForTouches:touches]) { + return; + } + + //[self setAnchorPoint:m_originalAnchorPoint]; // Notify the delegate we've ended our editing session. if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { @@ -373,14 +391,14 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { end.x = touchStart.y; end.y = touchPoint.x; - //} else if (-135.0 > rotationDeg) { - + //} else if (-135.0 > rotationDeg) { + } else if (rotationDeg > 135.0 || -135.0 > rotationDeg) { start = touchPoint; end = touchStart; } - + CGFloat deltaW = anchorPoint.adjustsW * (start.x - end.x) / scaleX; CGFloat deltaX = anchorPoint.adjustsX * (-1.0 * deltaW); @@ -395,35 +413,35 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { // (4) If the new frame is too small, cancel the changes. if (newWidth < self.minWidth) { - newWidth = self.bounds.size.width; + newWidth = self.minWidth; newX = self.frame.origin.x; } if (newHeight < self.minHeight) { - newHeight = self.bounds.size.height; + newHeight = self.minHeight; newY = self.frame.origin.y; } // (5) Ensure the resize won't cause the view to move offscreen. if (self.preventsPositionOutsideSuperview) { /* - if (newX < self.superview.bounds.origin.x) { - // Calculate how much to grow the width by such that the new X coordintae will align with the superview. - deltaW = self.frame.origin.x - self.superview.bounds.origin.x; - newWidth = self.frame.size.width + deltaW; - newX = self.superview.bounds.origin.x; - } - if (newX + newWidth > self.superview.bounds.origin.x + self.superview.bounds.size.width) { - newWidth = self.superview.bounds.size.width - newX; - } - if (newY < self.superview.bounds.origin.y) { - // Calculate how much to grow the height by such that the new Y coordintae will align with the superview. - deltaH = self.bounds.origin.y - self.superview.bounds.origin.y; - newHeight = self.frame.size.height + deltaH; - newY = self.superview.bounds.origin.y; - } - if (newY + newHeight > self.superview.bounds.origin.y + self.superview.bounds.size.height) { - newHeight = self.superview.bounds.size.height - newY; - }*/ + if (newX < self.superview.bounds.origin.x) { + // Calculate how much to grow the width by such that the new X coordintae will align with the superview. + deltaW = self.frame.origin.x - self.superview.bounds.origin.x; + newWidth = self.frame.size.width + deltaW; + newX = self.superview.bounds.origin.x; + } + if (newX + newWidth > self.superview.bounds.origin.x + self.superview.bounds.size.width) { + newWidth = self.superview.bounds.size.width - newX; + } + if (newY < self.superview.bounds.origin.y) { + // Calculate how much to grow the height by such that the new Y coordintae will align with the superview. + deltaH = self.bounds.origin.y - self.superview.bounds.origin.y; + newHeight = self.frame.size.height + deltaH; + newY = self.superview.bounds.origin.y; + } + if (newY + newHeight > self.superview.bounds.origin.y + self.superview.bounds.size.height) { + newHeight = self.superview.bounds.size.height - newY; + }*/ } // update the frame @@ -442,7 +460,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { } - (void)translateUsingTouchLocation:(CGPoint)touchPoint { - [self setAnchorPoint:CGPointMake(0.5, 0.5)]; + //[self setAnchorPoint:CGPointMake(0.5, 0.5)]; CGPoint newCenter = CGPointMake(self.center.x + touchPoint.x - touchStart.x, self.center.y + touchPoint.y - touchStart.y); @@ -490,8 +508,10 @@ -(void)setAnchorPoint:(CGPoint)anchor { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // is disabled or there are more touches if (![self isDisabledForTouches:touches]) { - if ([self isResizing]) { - [self resizeUsingTouchLocation:[[touches anyObject] locationInView:self.superview]]; + CGPoint point = [[touches anyObject] locationInView:self.superview]; + + if ([self isResizing] && [touches count] == 1 && [self willResize:point]) { + [self resizeUsingTouchLocation:point]; } else if (![self disablePan]){ [self translateUsingTouchLocation:[[touches anyObject] locationInView:self]]; } diff --git a/SPUserResizableView/ViewController.m b/SPUserResizableView/ViewController.m index e1968ea..0ee32c0 100644 --- a/SPUserResizableView/ViewController.m +++ b/SPUserResizableView/ViewController.m @@ -39,7 +39,7 @@ - (void)viewDidLoad { imageResizableView.contentView = imageView; imageResizableView.delegate = self; - imageResizableView.disablePan = YES; + imageResizableView.disablePan = NO; [imageResizableView setTransform:CGAffineTransformMakeRotation(0.1)]; From ffe8db16d5ab11645146d425b492f47a4ef150de Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Mon, 27 Oct 2014 16:37:17 +0100 Subject: [PATCH 06/15] - disabled outside of bounds on pan - improved resize when pan is enabled --- .../UserInterfaceState.xcuserstate | Bin 19755 -> 20373 bytes SPUserResizableView/SPUserResizableView.m | 12 ++++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate b/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate index c3964a21f0927fddc8c4284c1cab9afac57588e7..15245431030675e370ba0d964f57b29467ccc729 100644 GIT binary patch delta 11230 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 delta 11086 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 diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index ad03983..3d1f905 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -184,6 +184,7 @@ - (void)setContentView:(UIView *)newContentView { // Ensure the border view is always on top by removing it and adding it to the end of the subview list. [borderView removeFromSuperview]; [self addSubview:borderView]; + [self setFrame:[self frame]]; } - (void)setFrame:(CGRect)newFrame { @@ -464,8 +465,9 @@ - (void)translateUsingTouchLocation:(CGPoint)touchPoint { CGPoint newCenter = CGPointMake(self.center.x + touchPoint.x - touchStart.x, self.center.y + touchPoint.y - touchStart.y); - if (self.preventsPositionOutsideSuperview) { + if (self.preventsPositionOutsideSuperview) {/* // Ensure the translation won't cause the view to move offscreen. + CGFloat midPointX = CGRectGetMidX(self.bounds); if (newCenter.x > self.superview.bounds.size.width - midPointX) { newCenter.x = self.superview.bounds.size.width - midPointX; @@ -479,7 +481,7 @@ - (void)translateUsingTouchLocation:(CGPoint)touchPoint { } if (newCenter.y < midPointY) { newCenter.y = midPointY; - } + }*/ } self.center = newCenter; } @@ -510,8 +512,10 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (![self isDisabledForTouches:touches]) { CGPoint point = [[touches anyObject] locationInView:self.superview]; - if ([self isResizing] && [touches count] == 1 && [self willResize:point]) { - [self resizeUsingTouchLocation:point]; + if ([self isResizing] && [touches count] == 1) { + if ([self willResize:point]) { + [self resizeUsingTouchLocation:point]; + } } else if (![self disablePan]){ [self translateUsingTouchLocation:[[touches anyObject] locationInView:self]]; } From 61368d65b46eadab87548dde377c0f7aad0031df Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Wed, 29 Oct 2014 12:15:27 +0100 Subject: [PATCH 07/15] - structure improvments in code - added change detection to ensure that didEnd will be fired even if its disabled --- .../UserInterfaceState.xcuserstate | Bin 20373 -> 20471 bytes SPUserResizableView/SPUserResizableView.h | 1 + SPUserResizableView/SPUserResizableView.m | 241 +++++++++--------- 3 files changed, 128 insertions(+), 114 deletions(-) diff --git a/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate b/SPUserResizableView.xcodeproj/project.xcworkspace/xcuserdata/pion.xcuserdatad/UserInterfaceState.xcuserstate index 15245431030675e370ba0d964f57b29467ccc729..f74c250f2f1220976c824047994b7e859d894e9f 100644 GIT binary patch delta 11411 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 delegate; diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 3d1f905..037ea1c 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -117,6 +117,13 @@ - (BOOL)isDisabledForTouches:(NSSet*)touches; */ - (BOOL)willResize:(CGPoint)point; +/** + * Triggered when touches finished or canceled + * + * @param touches + */ +- (void)touchesFinished:(NSSet *)touches; + @end @implementation SPUserResizableView @@ -197,53 +204,6 @@ - (void)setFrame:(CGRect)newFrame { } } -static CGFloat SPDistanceBetweenTwoPoints(CGPoint point1, CGPoint point2) { - CGFloat dx = point2.x - point1.x; - CGFloat dy = point2.y - point1.y; - return sqrt(dx*dx + dy*dy); -}; - -typedef struct CGPointSPUserResizableViewAnchorPointPair { - CGPoint point; - SPUserResizableViewAnchorPoint anchorPoint; -} CGPointSPUserResizableViewAnchorPointPair; - -- (SPUserResizableViewAnchorPoint)anchorPointForTouchLocation:(CGPoint)touchPoint { - - - // (1) Calculate the positions of each of the anchor points. - CGPointSPUserResizableViewAnchorPointPair upperLeft = { CGPointMake(0.0, 0.0), SPUserResizableViewUpperLeftAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair upperMiddle = { CGPointMake(self.bounds.size.width/2, 0.0), SPUserResizableViewUpperMiddleAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair upperRight = { CGPointMake(self.bounds.size.width, 0.0), SPUserResizableViewUpperRightAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair middleRight = { CGPointMake(self.bounds.size.width, self.bounds.size.height/2), SPUserResizableViewMiddleRightAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair lowerRight = { CGPointMake(self.bounds.size.width, self.bounds.size.height), SPUserResizableViewLowerRightAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair lowerMiddle = { CGPointMake(self.bounds.size.width/2, self.bounds.size.height), SPUserResizableViewLowerMiddleAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair lowerLeft = { CGPointMake(0, self.bounds.size.height), SPUserResizableViewLowerLeftAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair middleLeft = { CGPointMake(0, self.bounds.size.height/2), SPUserResizableViewMiddleLeftAnchorPoint }; - CGPointSPUserResizableViewAnchorPointPair centerPoint = { CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2), SPUserResizableViewNoResizeAnchorPoint }; - - // (2) Iterate over each of the anchor points and find the one closest to the user's touch. - CGPointSPUserResizableViewAnchorPointPair allPoints[9] = { upperLeft, upperRight, lowerRight, lowerLeft, upperMiddle, lowerMiddle, middleLeft, middleRight, centerPoint }; - CGFloat smallestDistance = MAXFLOAT; CGPointSPUserResizableViewAnchorPointPair closestPoint = centerPoint; - for (NSInteger i = 0; i < 9; i++) { - CGFloat distance = SPDistanceBetweenTwoPoints(touchPoint, allPoints[i].point); - if (distance < smallestDistance) { - closestPoint = allPoints[i]; - smallestDistance = distance; - } - } - - - // make dragable only small portion of border. - float check = ([self resizableInset]+5) * 2; - - if (touchPoint.x < check+[self resizableInset] || touchPoint.x >= (self.bounds.size.width-check) || touchPoint.y < check+[self resizableInset] || touchPoint.y >= (self.bounds.size.height-check)) { - return closestPoint.anchorPoint; - } else { - return (SPUserResizableViewAnchorPoint){0,0,0,0}; - } -} - - (BOOL)isResizing { return (anchorPoint.adjustsH || anchorPoint.adjustsW || anchorPoint.adjustsX || anchorPoint.adjustsY); } @@ -257,56 +217,6 @@ - (BOOL)willResize:(CGPoint)point { return [self isResizing] && (point.x != touchStart.x && point.y != touchStart.y); } -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - if ([self isDisabledForTouches:touches]) { - return; - } - - //m_originalAnchorPoint = [[self layer] anchorPoint]; - - // Notify the delegate we've begun our editing session. - if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidBeginEditing:)]) { - [self.delegate userResizableViewDidBeginEditing:self]; - } - - [borderView setHidden:NO]; - UITouch *touch = [touches anyObject]; - - anchorPoint = [self anchorPointForTouchLocation:[touch locationInView:self]]; - - // When resizing, all calculations are done in the superview's coordinate space. - touchStart = [touch locationInView:self.superview]; - if (![self isResizing]) { - // When translating, all calculations are done in the view's coordinate space. - touchStart = [touch locationInView:self]; - } -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - if ([self isDisabledForTouches:touches]) { - return; - } - //[self setAnchorPoint:m_originalAnchorPoint]; - - // Notify the delegate we've ended our editing session. - if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { - [self.delegate userResizableViewDidEndEditing:self]; - } -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - if ([self isDisabledForTouches:touches]) { - return; - } - - //[self setAnchorPoint:m_originalAnchorPoint]; - - // Notify the delegate we've ended our editing session. - if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { - [self.delegate userResizableViewDidEndEditing:self]; - } -} - - (void)showEditingHandles { [borderView setHidden:NO]; } @@ -315,6 +225,8 @@ - (void)hideEditingHandles { [borderView setHidden:YES]; } +#pragma mark - Resize + - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { if ([self disable]) { return; @@ -460,33 +372,35 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { touchStart = touchPoint; } +#pragma mark - Helper functions + - (void)translateUsingTouchLocation:(CGPoint)touchPoint { //[self setAnchorPoint:CGPointMake(0.5, 0.5)]; CGPoint newCenter = CGPointMake(self.center.x + touchPoint.x - touchStart.x, self.center.y + touchPoint.y - touchStart.y); if (self.preventsPositionOutsideSuperview) {/* - // Ensure the translation won't cause the view to move offscreen. - - CGFloat midPointX = CGRectGetMidX(self.bounds); - if (newCenter.x > self.superview.bounds.size.width - midPointX) { - newCenter.x = self.superview.bounds.size.width - midPointX; - } - if (newCenter.x < midPointX) { - newCenter.x = midPointX; - } - CGFloat midPointY = CGRectGetMidY(self.bounds); - if (newCenter.y > self.superview.bounds.size.height - midPointY) { - newCenter.y = self.superview.bounds.size.height - midPointY; - } - if (newCenter.y < midPointY) { - newCenter.y = midPointY; - }*/ + // Ensure the translation won't cause the view to move offscreen. + + CGFloat midPointX = CGRectGetMidX(self.bounds); + if (newCenter.x > self.superview.bounds.size.width - midPointX) { + newCenter.x = self.superview.bounds.size.width - midPointX; + } + if (newCenter.x < midPointX) { + newCenter.x = midPointX; + } + CGFloat midPointY = CGRectGetMidY(self.bounds); + if (newCenter.y > self.superview.bounds.size.height - midPointY) { + newCenter.y = self.superview.bounds.size.height - midPointY; + } + if (newCenter.y < midPointY) { + newCenter.y = midPointY; + }*/ } self.center = newCenter; } --(void)setAnchorPoint:(CGPoint)anchor { +- (void)setAnchorPoint:(CGPoint)anchor { CGPoint newPoint = CGPointMake(self.bounds.size.width * anchor.x, self.bounds.size.height * anchor.y); CGPoint oldPoint = CGPointMake(self.bounds.size.width * self.layer.anchorPoint.x, @@ -507,6 +421,102 @@ -(void)setAnchorPoint:(CGPoint)anchor { self.layer.anchorPoint = anchor; } + + +static CGFloat SPDistanceBetweenTwoPoints(CGPoint point1, CGPoint point2) { + CGFloat dx = point2.x - point1.x; + CGFloat dy = point2.y - point1.y; + return sqrt(dx*dx + dy*dy); +}; + +typedef struct CGPointSPUserResizableViewAnchorPointPair { + CGPoint point; + SPUserResizableViewAnchorPoint anchorPoint; +} CGPointSPUserResizableViewAnchorPointPair; + +- (SPUserResizableViewAnchorPoint)anchorPointForTouchLocation:(CGPoint)touchPoint { + + + // (1) Calculate the positions of each of the anchor points. + CGPointSPUserResizableViewAnchorPointPair upperLeft = { CGPointMake(0.0, 0.0), SPUserResizableViewUpperLeftAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair upperMiddle = { CGPointMake(self.bounds.size.width/2, 0.0), SPUserResizableViewUpperMiddleAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair upperRight = { CGPointMake(self.bounds.size.width, 0.0), SPUserResizableViewUpperRightAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair middleRight = { CGPointMake(self.bounds.size.width, self.bounds.size.height/2), SPUserResizableViewMiddleRightAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair lowerRight = { CGPointMake(self.bounds.size.width, self.bounds.size.height), SPUserResizableViewLowerRightAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair lowerMiddle = { CGPointMake(self.bounds.size.width/2, self.bounds.size.height), SPUserResizableViewLowerMiddleAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair lowerLeft = { CGPointMake(0, self.bounds.size.height), SPUserResizableViewLowerLeftAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair middleLeft = { CGPointMake(0, self.bounds.size.height/2), SPUserResizableViewMiddleLeftAnchorPoint }; + CGPointSPUserResizableViewAnchorPointPair centerPoint = { CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2), SPUserResizableViewNoResizeAnchorPoint }; + + // (2) Iterate over each of the anchor points and find the one closest to the user's touch. + CGPointSPUserResizableViewAnchorPointPair allPoints[9] = { upperLeft, upperRight, lowerRight, lowerLeft, upperMiddle, lowerMiddle, middleLeft, middleRight, centerPoint }; + CGFloat smallestDistance = MAXFLOAT; CGPointSPUserResizableViewAnchorPointPair closestPoint = centerPoint; + for (NSInteger i = 0; i < 9; i++) { + CGFloat distance = SPDistanceBetweenTwoPoints(touchPoint, allPoints[i].point); + if (distance < smallestDistance) { + closestPoint = allPoints[i]; + smallestDistance = distance; + } + } + + + // make dragable only small portion of border. + float check = ([self resizableInset]+5) * 2; + + if (touchPoint.x < check+[self resizableInset] || touchPoint.x >= (self.bounds.size.width-check) || touchPoint.y < check+[self resizableInset] || touchPoint.y >= (self.bounds.size.height-check)) { + return closestPoint.anchorPoint; + } else { + return (SPUserResizableViewAnchorPoint){0,0,0,0}; + } +} + +#pragma mark - Touches + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + if ([self isDisabledForTouches:touches]) { + return; + } + + //m_originalAnchorPoint = [[self layer] anchorPoint]; + + // Notify the delegate we've begun our editing session. + if (self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidBeginEditing:)]) { + [self.delegate userResizableViewDidBeginEditing:self]; + } + + [borderView setHidden:NO]; + UITouch *touch = [touches anyObject]; + + anchorPoint = [self anchorPointForTouchLocation:[touch locationInView:self]]; + + // When resizing, all calculations are done in the superview's coordinate space. + touchStart = [touch locationInView:self.superview]; + if (![self isResizing]) { + // When translating, all calculations are done in the view's coordinate space. + touchStart = [touch locationInView:self]; + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [self touchesFinished:touches]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [self touchesFinished:touches]; +} + +- (void)touchesFinished:(NSSet *)touches { + if ((didMakeChange || ![self disable]) && self.delegate && [self.delegate respondsToSelector:@selector(userResizableViewDidEndEditing:)]) { + [self.delegate userResizableViewDidEndEditing:self]; + } + + didMakeChange = NO; + + if ([self isDisabledForTouches:touches]) { + return; + } +} + - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // is disabled or there are more touches if (![self isDisabledForTouches:touches]) { @@ -514,9 +524,12 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if ([self isResizing] && [touches count] == 1) { if ([self willResize:point]) { + didMakeChange = YES; [self resizeUsingTouchLocation:point]; } } else if (![self disablePan]){ + didMakeChange = YES; + [self translateUsingTouchLocation:[[touches anyObject] locationInView:self]]; } } From 1b5b6d06fdb0ba491f6d8c76d31383ea3cc43d90 Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Wed, 29 Oct 2014 12:19:28 +0100 Subject: [PATCH 08/15] - structure improvments in code - added change detection to ensure that didEnd will be fired even if its disabled, \d updated readme --- README.md | 56 +++++++++++++++++++++++ SPUserResizableView/SPUserResizableView.h | 3 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8751dde..bbdd132 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,26 @@ userResizableView.delegate = self; Then implement the following delegate methods. ``` objective-c +/** + * Called when the resizable view receives touchesBegan: and activates the editing handles. + * + * @param userResizableView + */ - (void)userResizableViewDidBeginEditing:(SPUserResizableView *)userResizableView; + +/** + * Called when the resizable view receives touchesEnded: or touchesCancelled: + * + * @param userResizableView + */ - (void)userResizableViewDidEndEditing:(SPUserResizableView *)userResizableView; + +/** + * Called when new frame was set. + * + * @param userResizableView + */ +- (void)userResizableViewNewRealFrame:(SPUserResizableView *)userResizableView; ``` By default, SPUserResizableView will show the editing handles (as seen in the screenshot above) whenever it receives a touch event. The editing handles will remain visible even after the userResizableViewDidEndEditing: message is sent. This is to provide visual feedback to the user that the view is indeed moveable and resizable. If you'd like to dismiss the editing handles, you must explicitly call -hideEditingHandles. @@ -53,9 +71,47 @@ By default, SPUserResizableView will show the editing handles (as seen in the sc The SPUserResizableView is customizable using the following properties: ``` objective-c +/** + * Minimum width to let user resize + * @default Default is 48.0 for each. + */ @property (nonatomic) CGFloat minWidth; +/** + * Minimum height that will let user to resize + */ @property (nonatomic) CGFloat minHeight; + +/** + * Disables resize of the view + * @default NO + */ +@property (nonatomic) BOOL disable; + +/** + * Disables resize of the view if user use more than 1 finger. + * @default NO + */ +@property (nonatomic) BOOL disableOnMultiTouch; +/** + * Defaults to YES. Disables the user from dragging the view outside the parent view's bounds. + */ @property (nonatomic) BOOL preventsPositionOutsideSuperview; + +/** + * Defines if pan is disabled. + * @default NO + */ +@property (nonatomic) BOOL disablePan; + +/** + * Defines the insent of the content. + * Larger == better detection + */ +@property (nonatomic) float resizableInset; +/** + * Interactive border size + */ +@property (nonatomic) float interactiveBorderSize; ``` For an example of how to use SPUserResizableView, please see the included example project. diff --git a/SPUserResizableView/SPUserResizableView.h b/SPUserResizableView/SPUserResizableView.h index 23b036c..c112e8a 100644 --- a/SPUserResizableView/SPUserResizableView.h +++ b/SPUserResizableView/SPUserResizableView.h @@ -56,6 +56,7 @@ typedef struct SPUserResizableViewAnchorPoint { */ @property (nonatomic, weak) UIView *contentView; +#pragma mark - Setup properties /** * Minimum width to let user resize * @default Default is 48.0 for each. @@ -139,6 +140,6 @@ typedef struct SPUserResizableViewAnchorPoint { * * @param userResizableView */ -- (void)userResizableViewNewRealFrame:(SPUserResizableView *)userResizableView;; +- (void)userResizableViewNewRealFrame:(SPUserResizableView *)userResizableView; @end From 6ec94b6a3c491c59916d55a609bcc8563edffc4c Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Wed, 29 Oct 2014 12:20:33 +0100 Subject: [PATCH 09/15] Updated podspec --- SPUserResizableView+Pion.podspec | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 SPUserResizableView+Pion.podspec diff --git a/SPUserResizableView+Pion.podspec b/SPUserResizableView+Pion.podspec new file mode 100644 index 0000000..0763f11 --- /dev/null +++ b/SPUserResizableView+Pion.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |s| + s.name = 'SPUserResizableView+Pion' + s.version = '0.5.3' + s.license = 'MIT' + s.homepage = 'https://github.com/pionl/SPUserResizableView' + s.authors = 'Stephen Poletto' + s.summary = 'A forked (originaly from STephen Poletto) SPUserResizableView is a user-resizable, user-repositionable UIView subclass. ' + +# Source Info + s.platform = :ios, '5.0' + s.source = {:git => 'https://github.com/pionl/SPUserResizableView.git', :tag => '0.5.2'} + s.source_files = 'SPUserResizableView/SPUserResizableView.{h,m}' + s.requires_arc = true + +# Pod Dependencies + +end From 9f419d2e16be01d13e22dfb0eec034a3fa7f4536 Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Wed, 29 Oct 2014 12:30:35 +0100 Subject: [PATCH 10/15] Updated podspec --- SPUserResizableView+Pion.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SPUserResizableView+Pion.podspec b/SPUserResizableView+Pion.podspec index 0763f11..16b8791 100644 --- a/SPUserResizableView+Pion.podspec +++ b/SPUserResizableView+Pion.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| # Source Info s.platform = :ios, '5.0' - s.source = {:git => 'https://github.com/pionl/SPUserResizableView.git', :tag => '0.5.2'} + s.source = {:git => 'https://github.com/pionl/SPUserResizableView.git', :tag => '0.5.3'} s.source_files = 'SPUserResizableView/SPUserResizableView.{h,m}' s.requires_arc = true From 51113ef86dd31e6b70dd93dcfad61beb81abb606 Mon Sep 17 00:00:00 2001 From: Dmitry Yudakov Date: Wed, 13 Apr 2016 14:27:56 +0300 Subject: [PATCH 11/15] Fixed jumping effect in case minHeight/minWidth is reached When you resize the element with upper/left anchors and reach either min height or min width the element sort of "jumps" up/left. It happens because element's size is increased exceptionally setting it to minWidth/minHeight while calculated newWidth/newHeight was smaller. The bad thing is that newX/newY are not recalculated in this case which leads to jumping effect. The fix is decreasing newX/newY with same amount as newWidth/newHeight are increased with thus leaving the element at the same place. --- SPUserResizableView/SPUserResizableView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 037ea1c..39a9f29 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -326,12 +326,12 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { // (4) If the new frame is too small, cancel the changes. if (newWidth < self.minWidth) { + newX -= self.minWidth - newWidth; newWidth = self.minWidth; - newX = self.frame.origin.x; } if (newHeight < self.minHeight) { + newY -= self.minHeight - newHeight; newHeight = self.minHeight; - newY = self.frame.origin.y; } // (5) Ensure the resize won't cause the view to move offscreen. From ef20cf6fe7022cfe1751cdabd129d97e71c36655 Mon Sep 17 00:00:00 2001 From: Dmitry Yudakov Date: Wed, 13 Apr 2016 14:31:07 +0300 Subject: [PATCH 12/15] Updated podspec --- SPUserResizableView+Pion.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SPUserResizableView+Pion.podspec b/SPUserResizableView+Pion.podspec index 16b8791..fbabb2a 100644 --- a/SPUserResizableView+Pion.podspec +++ b/SPUserResizableView+Pion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SPUserResizableView+Pion' - s.version = '0.5.3' + s.version = '0.5.4' s.license = 'MIT' s.homepage = 'https://github.com/pionl/SPUserResizableView' s.authors = 'Stephen Poletto' @@ -8,7 +8,7 @@ Pod::Spec.new do |s| # Source Info s.platform = :ios, '5.0' - s.source = {:git => 'https://github.com/pionl/SPUserResizableView.git', :tag => '0.5.3'} + s.source = {:git => 'https://github.com/pionl/SPUserResizableView.git', :tag => '0.5.4'} s.source_files = 'SPUserResizableView/SPUserResizableView.{h,m}' s.requires_arc = true From 7b81adf68134b11e6c5b8357576e32acd2b60a61 Mon Sep 17 00:00:00 2001 From: Dmitry Yudakov Date: Thu, 14 Apr 2016 11:04:10 +0300 Subject: [PATCH 13/15] Fixed moving minHeight/minWidth element when resizing with bottom/right anchor --- SPUserResizableView/SPUserResizableView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index 39a9f29..e0fa85b 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -326,11 +326,11 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { // (4) If the new frame is too small, cancel the changes. if (newWidth < self.minWidth) { - newX -= self.minWidth - newWidth; + newX -= anchorPoint.adjustsX * (self.minWidth - newWidth); newWidth = self.minWidth; } if (newHeight < self.minHeight) { - newY -= self.minHeight - newHeight; + newY -= anchorPoint.adjustsY * (self.minHeight - newHeight); newHeight = self.minHeight; } From b0439f9acfeb88966bb47e295116499638cdf493 Mon Sep 17 00:00:00 2001 From: Dmitry Yudakov Date: Thu, 14 Apr 2016 11:12:46 +0300 Subject: [PATCH 14/15] Fixed building demo project in Xcode 7.3 --- SPUserResizableView.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SPUserResizableView.xcodeproj/project.pbxproj b/SPUserResizableView.xcodeproj/project.pbxproj index c6d2f33..85f344d 100644 --- a/SPUserResizableView.xcodeproj/project.pbxproj +++ b/SPUserResizableView.xcodeproj/project.pbxproj @@ -192,8 +192,10 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ENABLE_OBJC_WEAK = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -216,8 +218,10 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ENABLE_OBJC_WEAK = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; From bca76aa2b81ffc9158b8dca00d5fdaa097f49b5f Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Thu, 14 Apr 2016 12:36:51 +0200 Subject: [PATCH 15/15] removed NSLog + added gitignore --- .gitignore | 27 +++++++++++++++++++++++ SPUserResizableView/SPUserResizableView.m | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af884f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Created by https://www.gitignore.io/api/xcode + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + diff --git a/SPUserResizableView/SPUserResizableView.m b/SPUserResizableView/SPUserResizableView.m index e0fa85b..cbcab41 100644 --- a/SPUserResizableView/SPUserResizableView.m +++ b/SPUserResizableView/SPUserResizableView.m @@ -232,7 +232,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { return; } - NSLog(@"Touch point %@",NSStringFromCGPoint(touchPoint)); + //NSLog(@"Touch point %@",NSStringFromCGPoint(touchPoint)); // save current rotation and scales CGFloat scaleX = [[self valueForKeyPath:@"layer.transform.scale.x"] floatValue]; CGFloat scaleY = [[self valueForKeyPath:@"layer.transform.scale.y"] floatValue]; @@ -243,7 +243,7 @@ - (void)resizeUsingTouchLocation:(CGPoint)touchPoint { //NSLog(@"H %f, W %f, X %f, Y %f", anchorPoint.adjustsH, anchorPoint.adjustsW, anchorPoint.adjustsX, anchorPoint.adjustsY); - NSLog(@"Rotation %f",RADIANS_TO_DEGREES(rotation)); + //NSLog(@"Rotation %f",RADIANS_TO_DEGREES(rotation)); CGPoint point;