Skip to content

Instantly share code, notes, and snippets.

@marchold
Created November 3, 2014 18:25
Show Gist options
  • Save marchold/a4348ecd7978194d39e9 to your computer and use it in GitHub Desktop.
Save marchold/a4348ecd7978194d39e9 to your computer and use it in GitHub Desktop.
A resizable image view, never fully worked but the affine transform stuff in it is solid
#import <UIKit/UIKit.h>
CGFloat CGAffineTransformGetScaleX(CGAffineTransform t);
CGFloat CGAffineTransformGetScaleY(CGAffineTransform t);
CGFloat CGAffineTransformGetRotation(CGAffineTransform t);
CGFloat CGAffineTransformGetTranslationX(CGAffineTransform t);
CGFloat CGAffineTransformGetTranslationY(CGAffineTransform t);
CGAffineTransform CGAffineTransformFromRectToRect(CGRect fromRect, CGRect toRect);
CGAffineTransform CGAffineTransformFromRectToRectKeepAspectRatio( CGRect fromRect, CGRect toRect );
CGPoint offsetPointToCoordinates(CGPoint parentCenterPoint, CGPoint pointToOffset);
#import "CGAffineTransform_Additions.h"
CGFloat CGAffineTransformGetScaleX(CGAffineTransform t)
{
return sqrt(t.a * t.a + t.c * t.c);
}
CGFloat CGAffineTransformGetScaleY(CGAffineTransform t)
{
return sqrt(t.b * t.b + t.d * t.d);
}
CGFloat CGAffineTransformGetRotation(CGAffineTransform t)
{
return atan2f(t.b, t.a);
}
CGFloat CGAffineTransformGetTranslationX(CGAffineTransform t)
{
return t.tx;
}
CGFloat CGAffineTransformGetTranslationY(CGAffineTransform t)
{
return t.ty;
}
CGAffineTransform CGAffineTransformFromRectToRect(CGRect fromRect, CGRect toRect)
{
CGAffineTransform trans1 = CGAffineTransformMakeTranslation(-fromRect.origin.x, -fromRect.origin.y);
CGAffineTransform scale = CGAffineTransformMakeScale(toRect.size.width/fromRect.size.width, toRect.size.height/fromRect.size.height);
CGAffineTransform trans2 = CGAffineTransformMakeTranslation(toRect.origin.x, toRect.origin.y);
return CGAffineTransformConcat(CGAffineTransformConcat(trans1, scale), trans2);
}
CGAffineTransform CGAffineTransformFromRectToRectKeepAspectRatio( CGRect fromRect, CGRect toRect )
{
float aspectRatio = fromRect.size.width / fromRect.size.height;
if( aspectRatio > ( toRect.size.width / toRect.size.height ))
{
toRect = CGRectInset( toRect, 0, ( toRect.size.height - toRect.size.width / aspectRatio ) / 2.0f );
}
else
{
toRect = CGRectInset( toRect, ( toRect.size.width - toRect.size.height * aspectRatio ) / 2.0f, 0 );
}
return CGAffineTransformFromRectToRect( fromRect, toRect );
}
#import "ResizableImageView.h"
#import "CGAffineTransform_Additions.h"
#define MAXIMUM_SCALE 2
@interface ResizableImageView(){
UIPanGestureRecognizer *panGesture;
BOOL enableOtherGestureRecognizer;
CGFloat minimumScale;
CGRect vcFrame;
}
@property (nonatomic,retain) UIImage *originalImage;
@property (nonatomic,retain) UIScrollView *scrollView;
@end
@implementation PLResizableImageView
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
// [self initalize];
}
return self;
}
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// [self initalize];
}
return self;
}
-(CGRect)originalFrame
{
CGAffineTransform t = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.frame;
self.transform = t;
return originalFrame;
}
-(void)setImage:(UIImage *)image
{
self.originalImage = image;
minimumScale = self.frame.size.width/image.size.width;
CGFloat verticalScale = self.frame.size.height/image.size.height;
if (minimumScale > verticalScale) minimumScale=verticalScale;
NSLog(@"Initial Scale = %f",minimumScale);
CGAffineTransform transform = CGAffineTransformMakeScale(minimumScale, minimumScale);
self.transform = transform;
[super setImage:image];
}
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
-(BOOL)scrollViewShouldScroll{
return (CGAffineTransformGetScaleX(self.transform) == minimumScale);
}
-(void) initalize:(UIScrollView*)scrollView vc:(UIViewController*)vc
{
self.scrollView = scrollView;
self.userInteractionEnabled = YES;
self.contentMode = UIViewContentModeCenter;
self.clipsToBounds = YES;
enableOtherGestureRecognizer = YES;
// Pinch
UIPinchGestureRecognizer *pgr = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:@selector(pinch:)];
pgr.delegate = self;
[self addGestureRecognizer:pgr];
[self.scrollView addGestureRecognizer:pgr];
// Pan
panGesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(pan:)];
panGesture.delegate = self;
//[self addGestureRecognizer:panGesture];
[self.scrollView addGestureRecognizer:panGesture];
// Double Tap
UITapGestureRecognizer *dtgr = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(doubleTap:)];
dtgr.numberOfTapsRequired = 2;
dtgr.delegate = self;
[self addGestureRecognizer:dtgr];
[self.scrollView addGestureRecognizer:dtgr];
vcFrame = vc.view.frame;
[self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:panGesture];
}
-(CGPoint)offsetPointToCenterCoordinates:(CGPoint)aPoint
{
return CGPointMake(aPoint.x+self.center.x, aPoint.y+self.center.y);
}
-(CGPoint)pointInViewCenterTerms:(CGPoint)aPoint
{
return CGPointMake(aPoint.x-self.center.x, aPoint.y-self.center.y);
}
-(CGPoint)pointInTransformedView:(CGPoint)aPoint
{
CGPoint offsetItem = [self pointInViewCenterTerms:aPoint];
CGPoint updatedItem = CGPointApplyAffineTransform(offsetItem, self.transform);
return [self offsetPointToCenterCoordinates:updatedItem];
}
- (void)pinch:(UIPinchGestureRecognizer *)gesture
{
if ( gesture.state == UIGestureRecognizerStateEnded
|| gesture.state == UIGestureRecognizerStateChanged)
{
self.transform = CGAffineTransformScale(self.transform, gesture.scale , gesture.scale );
CGFloat scale = CGAffineTransformGetScaleX(self.transform);
if (scale < minimumScale)
{
CGFloat x = CGAffineTransformGetTranslationX(self.transform);
CGFloat y = CGAffineTransformGetTranslationY(self.transform);
self.transform = CGAffineTransformIdentity;
self.transform = CGAffineTransformScale(self.transform, minimumScale, minimumScale );
self.transform = CGAffineTransformTranslate(self.transform, x, y);
}
if (scale > MAXIMUM_SCALE)
{
CGFloat x = CGAffineTransformGetTranslationX(self.transform);
CGFloat y = CGAffineTransformGetTranslationY(self.transform);
self.transform = CGAffineTransformIdentity;
self.transform = CGAffineTransformScale(self.transform, MAXIMUM_SCALE, MAXIMUM_SCALE );
self.transform = CGAffineTransformTranslate(self.transform, x, y);
}
if (scale > minimumScale)
{
// self.scrollView.scrollEnabled = NO;
}
}
}
- (void)pan:(UIPanGestureRecognizer *)gesture
{
//Apply the translation from the gesture directly to our views transform matrix
CGPoint translation = [gesture translationInView:self];
CGAffineTransform transform = CGAffineTransformTranslate(self.transform, translation.x, translation.y);
self.transform = transform;
[gesture setTranslation:CGPointMake(0, 0) inView:self];
//In case we scrolled the image too far we need to translate the transform back
CGPoint topLeft = [self pointInTransformedView:self.originalFrame.origin];
CGPoint bottomRight = [self pointInTransformedView:CGPointMake(self.originalFrame.origin.x+self.originalFrame.size.width,
self.originalFrame.origin.y+self.originalFrame.size.height)];
if (topLeft.x > 0)
{
transform = CGAffineTransformFromRectToRect(self.frame,CGRectMake(0,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height));
self.transform = CGAffineTransformConcat(self.transform, transform);
}
if (topLeft.y > 0)
{
transform = CGAffineTransformFromRectToRect(self.frame,CGRectMake(self.frame.origin.x,
0,
self.frame.size.width,
self.frame.size.height));
self.transform = CGAffineTransformConcat(self.transform, transform);
}
if (bottomRight.x < vcFrame.size.width)
{
transform = CGAffineTransformFromRectToRect(self.frame,CGRectMake(self.frame.origin.x+(vcFrame.size.width-bottomRight.x),
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height));
self.transform = CGAffineTransformConcat(self.transform, transform);
}
if (bottomRight.y < vcFrame.size.height)
{
transform = CGAffineTransformFromRectToRect(self.frame,CGRectMake(self.frame.origin.x,
self.frame.origin.y+(vcFrame.size.height-bottomRight.y),
self.frame.size.width,
self.frame.size.height));
self.transform = CGAffineTransformConcat(self.transform, transform);
}
}
- (void)doubleTap:(UITapGestureRecognizer *)gesture
{
if(CGAffineTransformGetScaleX(self.transform) == minimumScale)
{
CGAffineTransform transform = CGAffineTransformMakeScale(1, 1);
self.transform = transform;
// self.scrollView.scrollEnabled = NO;
}
else
{
CGAffineTransform transform = CGAffineTransformMakeScale(minimumScale, minimumScale);
self.transform = transform;
// self.scrollView.scrollEnabled = YES;
}
}
@marchold
Copy link
Author

marchold commented Nov 3, 2014

I never did use this because it did not work well within a scroll view as I had hoped. I think this could be a good starting point for other matrix transform operations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment