The following code correctly pinches/zooms the container view, but only after it jumps to a scale of 1.0. How can I modify it so that the container view scales from it's current scale?
UIPinchGestureRecognizer *twoFingerPinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(twoFingerPinch:)];
[self.container addGestureRecognizer:twoFingerPinch];
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer
{
_scale = recognizer.scale;
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, _scale, _scale);
self.container.transform = tr;
}
In .h file, add:
CGFloat _lastScale;
In .m file,
- (id)init {
...
_lastScale = 1.0f;
...
}
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
_lastScale = 1.0f;
return;
}
CGFloat scale = 1.0f - (_lastScale - recognizer.scale);
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, scale, scale);
self.container.transform = tr;
_lastScale = recognizer.scale;
}
Here's how I do it:
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer {
static float initialDifference = 0.0;
static float oldScale = 1.0;
if (recognizer.state == UIGestureRecognizerStateBegan){
initialDifference = oldScale - recognizer.scale;
}
CGFloat scale = oldScale - (oldScale - recognizer.scale) + initialDifference;
myView.transform = CGAffineTransformScale(self.view.transform, scale, scale);
oldScale = scale;
}
Related
I have scrollview and added UIPinchGestureRecognizer to scrollview. Now on gesture event I have zoom in or out scrollview and its handle action is as following :
static float lastScale = 1.0;
- (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
}
}
I want to change contentSize in this method. Now, my question is that how to set scrollview content size so that after zoom out I can scroll to see all the content in scrollview.
Please help.
#interface HorizontalScrollView ()
{
UIView *container;
}
#end
#implementation HorizontalScrollView
#synthesize scrlView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
container = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.scrlView.frame.size.width, self.scrlView.frame.size.height)];
UIImage *image = [UIImage imageNamed:#"1.jpeg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = 215;
rect.size.width = self.scrlView.frame.size.width;
rect.origin = CGPointMake(0, 0);
imageView.frame = rect;
[container addSubview:imageView];
[scrlView addSubview:container];
self.scrlView.minimumZoomScale=1.0;
self.scrlView.maximumZoomScale=6.0;
self.scrlView.delegate=self;
// set the content size so it can be scrollable
[self.scrlView setContentSize:CGSizeMake(1*self.scrlView.frame.size.width, 0)];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return container;
}
When I apply panDetected like this, the image is moving everywhere on the screen. I just want this feature to at the top in specific rectangle. What should I change?
-(void) panDetected: (UIPanGestureRecognizer * ) panRecognizer {
CGPoint translation = [panRecognizer translationInView: self.documentImageView];
CGPoint imageViewPosition = self.documentImageView.center;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
self.documentImageView.center = imageViewPosition;
[panRecognizer setTranslation: CGPointZero inView: self.view];
}
And this one is just allowing me to zoom on the pic but only from middle point not every point on the pic.
-(void) handlePinchWithGestureRecognizer: (UIPinchGestureRecognizer * ) pinchGestureRecognizer {
CGFloat lastScale = 1.0;
if ([pinchGestureRecognizer state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [pinchGestureRecognizer scale];
}
if ([pinchGestureRecognizer state] == UIGestureRecognizerStateBegan || [pinchGestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGFloat currentScale = [
[
[pinchGestureRecognizer view].layer valueForKeyPath: #
"transform.scale"] floatValue];
// Constants to adjust the max/min values of zoom
const CGFloat kMaxScale = 1.15;
const CGFloat kMinScale = 1.0;
CGFloat newScale = 1 - (lastScale - [pinchGestureRecognizer scale]);
newScale = MIN(newScale, kMaxScale / currentScale);
newScale = MAX(newScale, kMinScale / currentScale);
self.documentImageView.transform = CGAffineTransformScale(self.documentImageView.transform, newScale, newScale);
lastScale = [pinchGestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call
}
}
-(void) setExtractedImageForTableView: (UIImage * ) extractedImage {
self.documentImageView.image = nil;
self.documentImageView = nil;
self.documentImageView = [
[UIImageView alloc] initWithImage: extractedImage];
self.documentImageView.userInteractionEnabled = YES;
UIPinchGestureRecognizer * pinchGestureRecognizer = [
[UIPinchGestureRecognizer alloc] initWithTarget: self action: #selector(handlePinchWithGestureRecognizer: )];
[self.documentImageView addGestureRecognizer: pinchGestureRecognizer];
UIPanGestureRecognizer * panRecognizer = [
[UIPanGestureRecognizer alloc] initWithTarget: self action: #selector(panDetected: )];
[self.documentImageView addGestureRecognizer: panRecognizer];
self.documentImageView.contentMode = UIViewContentModeScaleAspectFit;
if (!CGSizeEqualToSize(extractedImage.size, CGSizeZero)) {
self.documentImageView.frame = CGRectMake(CGRectGetMinX(self.view.frame), CGRectGetMinY(self.tableView.frame), CGRectGetWidth(self.view.frame), (extractedImage.size.height / extractedImage.size.width) * CGRectGetWidth(self.view.frame));
self.tableView.tableHeaderView = self.documentImageView;
[self.tableView setContentOffset: CGPointZero animated: YES];
CGRect frame = self.documentImageView.frame;
frame.size.height = self.documentImageView.frame.size.height + 100;
self.tableView.frame = CGRectMake(0, 0, 200, 200);
self.tableView.tableHeaderView.frame = frame;
}
}
You can use UIGestureRecognizerDelegate to acheve this.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
The method above asks the delegate if a gesture recognizer should receive an object representing a touch. Therefore, you can check touch location and return NO when its not in the desired area.
I have a UIImageView i am performing pinch zoom & move image on full zoom.I am able to move the image but the issue is even if the image is not zoomed in it still moves on the screen.Please tell me how can i prevent it?
Here is the code for that
#define MINIMUM_SCALE 0.5
#define MAXIMUM_SCALE 6.0
#property CGPoint translation;
- (void)pan:(UIPanGestureRecognizer *)gesture {
static CGPoint currentTranslation;
static CGFloat currentScale = 0;
if (gesture.state == UIGestureRecognizerStateBegan) {
currentTranslation = _translation;
currentScale = self.view.frame.size.width / self.view.bounds.size.width;
}
if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [gesture translationInView:self.view];
_translation.x = translation.x + currentTranslation.x;
_translation.y = translation.y + currentTranslation.y;
CGAffineTransform transform1 = CGAffineTransformMakeTranslation(_translation.x , _translation.y);
CGAffineTransform transform2 = CGAffineTransformMakeScale(currentScale, currentScale);
CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
self.view.transform = transform;
}
}
- (void)pinch:(UIPinchGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateChanged) {
// NSLog(#"gesture.scale = %f", gesture.scale);
CGFloat currentScale = self.view.frame.size.width / self.view.bounds.size.width;
CGFloat newScale = currentScale * gesture.scale;
if (newScale < MINIMUM_SCALE) {
newScale = MINIMUM_SCALE;
}
if (newScale > MAXIMUM_SCALE) {
newScale = MAXIMUM_SCALE;
}
CGAffineTransform transform1 = CGAffineTransformMakeTranslation(_translation.x, _translation.y);
CGAffineTransform transform2 = CGAffineTransformMakeScale(newScale, newScale);
CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
self.view.transform = transform;
gesture.scale = 1;
}
}
**PS:**ImageView should only move when image is zoomed otherwise it should not be moveable.
I suggest a different approach:
Create a UIScrollView add the UIImageView into the scrollView's contentView and allow scrolling and zooming on the scrollView.
To prevent scrolling when not zoomed, set setScrollEnabled to NO and enable it in scrollViewDidZoom if the zoomLevel reaches a custom threshold.
So sth. like this should make make it much easier what you're trying to accomplish with a lot less code.
- (void)viewDidLoad:(BOOL)animated {
[super viewDidLoad:animated];
self.scrollView.scrollEnabled = NO;
self.scrollView.minimumZoomScale = 1;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
if (scrollView.zoomLevel > 1) {
scrollView.scrollEnabled = YES;
} else {
scrollView.scrollEnabled = NO;
}
}
I re-post the code I gave you in your first question on the subject ( Pinch zoom shifting image to most left corner on iPad in iOS? ), because I think the way you do it does not work as expected ( as far as I have tested ).
The pinch zoom is supposed to zoom on the middle of the fingers, and not on the middle of the image. If you really want to apply the zoom on center, I have added a boolean property zoomOnCenter.
The boundaries checking is done in the translateBy method.
Here is a link on the xCode test project: https://drive.google.com/file/d/0B88aMtNA0z2aWVBIbGZGdVhpdWM/view?usp=sharing
Interface
#interface PinchViewController : UIViewController
#property(nonatomic,strong) IBOutlet UIView* contentView;
#property(nonatomic,assign) BOOL zoomOnCenter;
#end
Implementation
#implementation PinchViewController
{
CGPoint translation;
CGFloat scale;
CGAffineTransform scaleTransform;
CGAffineTransform translateTransform;
CGPoint previousTranslation;
CGFloat previousScale;
NSUInteger previousNumTouches;
}
-(void)viewDidLoad
{
scale = 1.0f;
scaleTransform = CGAffineTransformIdentity;
translateTransform = CGAffineTransformIdentity;
previousTranslation = CGPointZero;
previousNumTouches = 0;
UIPinchGestureRecognizer *pinch=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:#selector(handlePinch:)];
[self.view addGestureRecognizer:pinch];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panGesture];
}
-(void)handlePinch:(UIPinchGestureRecognizer*)recognizer
{
// 1 - find pinch center
CGPoint mid = self.zoomOnCenter ? CGPointZero : [self computePinchCenter:recognizer];
mid.x-= recognizer.view.bounds.size.width / 2.0f;
mid.y-= recognizer.view.bounds.size.height / 2.0f;
// 2 - compute deltas
NSUInteger numTouches = recognizer.numberOfTouches;
if ( (recognizer.state==UIGestureRecognizerStateBegan) || ( previousNumTouches != numTouches ) ) {
previousScale = recognizer.scale;
previousTranslation = mid;
previousNumTouches = numTouches;
}
CGFloat deltaScale = ( recognizer.scale - previousScale ) * scale;
previousScale = recognizer.scale;
CGPoint deltaTranslation = CGPointMake(mid.x-previousTranslation.x, mid.y-previousTranslation.y);
previousTranslation = mid;
deltaTranslation.x/=scale;
deltaTranslation.y/=scale;
// 3 - apply
scale+=deltaScale;
if (scale<0.01) scale = 0.01; else if (scale>10) scale = 10;
scaleTransform = CGAffineTransformMakeScale(scale, scale);
[self translateBy:deltaTranslation];
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state==UIGestureRecognizerStateBegan) previousTranslation = CGPointZero;
CGPoint recognizerTranslation = [recognizer translationInView:self.contentView];
CGPoint deltaTranslation = CGPointMake(recognizerTranslation.x - previousTranslation.x,recognizerTranslation.y - previousTranslation.y);
previousTranslation = recognizerTranslation;
[self translateBy:deltaTranslation];
}
-(void)translateBy:(CGPoint)delta
{
CGSize contentSize = self.contentView.bounds.size;
CGSize viewSize = self.view.bounds.size;
CGSize scaledViewSize = viewSize;
scaledViewSize.width/=scale;
scaledViewSize.height/=scale;
CGPoint maxTranslation = CGPointMake( (contentSize.width-scaledViewSize.width) / 2.0f , (contentSize.height-scaledViewSize.height) / 2.0f );
if ( contentSize.width*scale < viewSize.width ) {
delta.x=0;
translation.x = 0;
} else {
translation.x+=delta.x;
if ( translation.x < - maxTranslation.x ) {
translation.x = - maxTranslation.x;
}
else if ( translation.x > maxTranslation.x ) {
translation.x = maxTranslation.x;
}
}
if ( contentSize.height*scale < viewSize.height ) {
delta.y=0; translation.y = 0;
} else {
translation.y+=delta.y;
if ( translation.y < - maxTranslation.y ) {
translation.y = - maxTranslation.y;
}
else if ( translation.y > maxTranslation.y ) {
translation.y = maxTranslation.y;
}
}
translateTransform = CGAffineTransformMakeTranslation(translation.x,translation.y);
self.contentView.transform = CGAffineTransformConcat(translateTransform,scaleTransform);
}
-(CGPoint)computePinchCenter:(UIPinchGestureRecognizer*)recognizer
{
// 1 - handle up to 3 touches
NSUInteger numTouches = recognizer.numberOfTouches;
if (numTouches>3) numTouches = 3;
// 2 - Find fingers middle point - with (0,0) being the center of the view
CGPoint pt1,pt2,pt3,mid;
switch (numTouches) {
case 3:
pt3 = [recognizer locationOfTouch:2 inView:recognizer.view];
case 2:
pt2 = [recognizer locationOfTouch:1 inView:recognizer.view];
case 1:
pt1 = [recognizer locationOfTouch:0 inView:recognizer.view];
}
switch (numTouches) {
case 3:
mid = CGPointMake( ( ( pt1.x + pt2.x ) / 2.0f + pt3.x ) / 2.0f, ( ( pt1.y + pt2.y ) / 2.0f + pt3.y ) / 2.0f );
break;
case 2:
mid = CGPointMake( ( pt1.x + pt2.x ) / 2.0f, ( pt1.y + pt2.y ) / 2.0f );
break;
case 1:
mid = CGPointMake( pt1.x, pt1.y);
break;
}
return mid;
}
#end
You can check the frame of your imageView and if it is same it means imageview has not been zoomed So you can disable the pan gesture if frame of imageview is same ......and if frame has changed then you can enable the pan gesture.....
I have a image in iOS. I have added pinch gesture on the image when i pinch the image it shifted to top left corner. I have also added pan gesture on image. When an image is zoomed then i am scrolling the image in every direction for that purpose i have added the pan gesture into the image.
My code is :
-(void)viewDidLoad
{
UIPinchGestureRecognizer *pinch=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:#selector(handlePinch:)];
[self.zoom_image addGestureRecognizer:pinch];
panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(moveImage:)];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.zoom_image addGestureRecognizer:panGesture];
img_center_x = self.zoom_image.center.x;
img_center_y = self.zoom_image.center.y;
}
-(void)handlePinch:(UIPinchGestureRecognizer*)sender
{
NSLog(#"latscale = %f",mLastScale);
mCurrentScale += [sender scale] - mLastScale;
mLastScale = [sender scale];
NSLog(#"before ceneter x %f",img_center_x);
NSLog(#"before ceneter x %f",img_center_y);
CGPoint img_center = CGPointMake(img_center_x, img_center_y);
self.zoom_image.center = img_center;
if (sender.state == UIGestureRecognizerStateEnded)
{
mLastScale = 1.0;
}
if(mCurrentScale<1.0)
{
mCurrentScale=1.0;
}
if(mCurrentScale>3.0)
{
mCurrentScale=3.0;
}
CGAffineTransform currentTransform = CGAffineTransformIdentity;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform,mCurrentScale, mCurrentScale);
self.zoom_image.transform = newTransform;
}
Pan gesture
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(moveImage:)];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.zoom_image addGestureRecognizer:panGesture];
move image:
- (void)moveImage:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self.zoom_image];
CGPoint location = [recognizer locationInView:self.view];
CGPoint initial=CGPointZero;
NSLog(#"%f\n%f",translation.x,translation.y);
NSLog(#"%f",self.zoom_image.frame.origin.y);
CGPoint finalpoint = CGPointMake(self.zoom_image.center.x + translation.x, self.zoom_image.center.y+ translation.y);
NSLog(#"%f",finalpoint.y);
//limit the boundary
if(recognizer.state==UIGestureRecognizerStateChanged)
{
if ((self.zoom_image.frame.origin.x>0 && translation.x > 0) || (self.zoom_image.frame.origin.x + self.zoom_image.frame.size.width<=self.view.frame.size.width && translation.x < 0))
finalpoint.x = self.zoom_image.center.x;
if ((self.zoom_image.frame.origin.y>100 && translation.y > 0) || (self.zoom_image.frame.origin.y + self.zoom_image.frame.size.height<=self.view.frame.size.height && translation.y < 0))
finalpoint.y = self.zoom_image.center.y;
//set final position
NSLog(#"%f",finalpoint.y);
self.zoom_image.center = finalpoint;
[recognizer setTranslation:initial inView:self.zoom_image];
}
}
Here is a possible solution.
• I've renamed your zoom_image by contentView, because this class can manipulate any view, not only images.
• I've removed the bound tests, and let the scale be in ( 0.01 - 10.0 )
• The pinch handle up to three fingers, and also acts as pan. Number of touches can be changed without interrupting the pinch.
There is still many things to improve, but the main principle is here :)
Interface ( properties like minScale,maxScale, minMargin and so are still to be added - why not a delegate )
#interface PinchViewController : UIViewController
#property(nonatomic,strong) IBOutlet UIView* contentView;
#end
Implementation
#implementation PinchViewController
{
CGPoint translation;
CGFloat scale;
CGAffineTransform scaleTransform;
CGAffineTransform translateTransform;
CGPoint previousTranslation;
CGFloat previousScale;
NSUInteger previousNumTouches;
}
-(void)viewDidLoad
{
scale = 1.0f;
scaleTransform = CGAffineTransformIdentity;
translateTransform = CGAffineTransformIdentity;
previousTranslation = CGPointZero;
previousNumTouches = 0;
UIPinchGestureRecognizer *pinch=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:#selector(handlePinch:)];
[self.view addGestureRecognizer:pinch];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panGesture];
}
-(void)handlePinch:(UIPinchGestureRecognizer*)recognizer
{
// 1 - find pinch center
CGPoint mid = [self computePinchCenter:recognizer];
mid.x-= recognizer.view.bounds.size.width / 2.0f;
mid.y-= recognizer.view.bounds.size.height / 2.0f;
// 2 - compute deltas
NSUInteger numTouches = recognizer.numberOfTouches;
if ( (recognizer.state==UIGestureRecognizerStateBegan) || ( previousNumTouches != numTouches ) ) {
previousScale = recognizer.scale;
previousTranslation = mid;
previousNumTouches = numTouches;
}
CGFloat deltaScale = ( recognizer.scale - previousScale ) * scale;
previousScale = recognizer.scale;
CGPoint deltaTranslation = CGPointMake(mid.x-previousTranslation.x, mid.y-previousTranslation.y);
previousTranslation = mid;
deltaTranslation.x/=scale;
deltaTranslation.y/=scale;
// 3 - apply
scale+=deltaScale;
if (scale<0.01) scale = 0.01; else if (scale>10) scale = 10;
scaleTransform = CGAffineTransformMakeScale(scale, scale);
[self translateBy:deltaTranslation];
NSLog(#"Translation : %.2f,%.2f - Scale Center : %.2f,%.2f - Scale : %.2f",deltaTranslation.x,deltaTranslation.y,mid.x,mid.y,scale);
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state==UIGestureRecognizerStateBegan) previousTranslation = CGPointZero;
CGPoint recognizerTranslation = [recognizer translationInView:self.contentView];
CGPoint deltaTranslation = CGPointMake(recognizerTranslation.x - previousTranslation.x,recognizerTranslation.y - previousTranslation.y);
previousTranslation = recognizerTranslation;
[self translateBy:deltaTranslation];
NSLog(#"Translation : %.2f,%.2f - Scale : %.2f",deltaTranslation.x,deltaTranslation.y,scale);
}
-(void)translateBy:(CGPoint)delta
{
translation.x+=delta.x;
translation.y+=delta.y;
translateTransform = CGAffineTransformMakeTranslation(translation.x,translation.y);
self.contentView.transform = CGAffineTransformConcat(translateTransform,scaleTransform);
}
-(CGPoint)computePinchCenter:(UIPinchGestureRecognizer*)recognizer
{
// 1 - handle up to 3 touches
NSUInteger numTouches = recognizer.numberOfTouches;
if (numTouches>3) numTouches = 3;
// 2 - Find fingers middle point - with (0,0) being the center of the view
CGPoint pt1,pt2,pt3,mid;
switch (numTouches) {
case 3:
pt3 = [recognizer locationOfTouch:2 inView:recognizer.view];
case 2:
pt2 = [recognizer locationOfTouch:1 inView:recognizer.view];
case 1:
pt1 = [recognizer locationOfTouch:0 inView:recognizer.view];
}
switch (numTouches) {
case 3:
mid = CGPointMake( ( ( pt1.x + pt2.x ) / 2.0f + pt3.x ) / 2.0f, ( ( pt1.y + pt2.y ) / 2.0f + pt3.y ) / 2.0f );
break;
case 2:
mid = CGPointMake( ( pt1.x + pt2.x ) / 2.0f, ( pt1.y + pt2.y ) / 2.0f );
break;
case 1:
mid = CGPointMake( pt1.x, pt1.y);
break;
}
return mid;
}
#end
Hope it will help :) Cheers
Using a UIPanGestureRecognizer in my view controller, I'm trying to draw a view (ArrowView) at an angle based upon the touch location. I'm trying to use CGAffineTransformRotate to rotate the view based up the angle between the first touch and the current touch, but this isn't working unless the view has already been drawn by at lease 20 or more pixels. Also, when drawing, the view doesn't always line up under my finger. Is this the correct approach for this situation? If not, does anyone recommend a better way of accomplishing this? If so, what am I doing wrong?
ViewController.m
#implementation ViewController {
ArrowView *_selectedArrowView;
UIColor *_selectedColor;
CGFloat _selectedWeight;
CGPoint _startPoint;
}
- (void)viewDidLoad {
[super viewDidLoad];
_selectedColor = [UIColor yellowColor];
_selectedWeight = 3;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panHandler:)];
[self.view addGestureRecognizer:pan];
}
- (void) panHandler: (UIPanGestureRecognizer *) sender {
if (sender.state == UIGestureRecognizerStateBegan) {
//Instantiate the arrow
CGPoint touchPoint = [sender locationInView:sender.view];
_startPoint = touchPoint;
_selectedArrowView = [[ArrowView alloc] initWithFrame:CGRectMake(touchPoint.x, touchPoint.y, 0, 25) withColor:_selectedColor withWeight:_selectedWeight];
_selectedArrowView.delegate = self;
[self.view addSubview:_selectedArrowView];
[self.view bringSubviewToFront:_selectedArrowView];
} else if (sender.state == UIGestureRecognizerStateChanged) {
//"Draw" the arrow based upon finger postion
CGPoint touchPoint = [sender locationInView:sender.view];
[_selectedArrowView drawArrow:_startPoint to:touchPoint];
}
}
#end
ArrowView.m
- (void) drawArrow: (CGPoint) startPoint to: (CGPoint) endPoint {
startPoint = [self convertPoint:startPoint fromView:self.superview];
endPoint = [self convertPoint:endPoint fromView:self.superview];
if (_initialAngle == -1000 /*Initially set to an arbitrary value so I know when the draw began*/) {
_initialAngle = atan2(startPoint.y - endPoint.y, startPoint.x - endPoint.x);
[self setPosition:0];
} else {
CGFloat ang = atan2(startPoint.y - endPoint.y, startPoint.x - endPoint.x);
ang -= _initialAngle;
self.transform = CGAffineTransformRotate(self.transform, ang);
CGFloat diff = (endPoint.x - self.bounds.size.width);
NSLog(#"\n\n diff: %f \n\n", diff);
self.bounds = CGRectMake(0, 0, self.bounds.size.width + diff, self.bounds.size.height);
_endPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height);
[self setNeedsDisplay];
}
}
- (void) setPosition: (CGFloat) anchorPointX {
CGPoint layerLoc;
if (anchorPointX == 0) {
layerLoc = CGPointMake(self.layer.bounds.origin.x, self.layer.bounds.origin.y + (self.layer.bounds.size.height / 2));
} else {
layerLoc = CGPointMake(self.layer.bounds.origin.x + self.layer.bounds.size.width, self.layer.bounds.origin.y + (self.layer.bounds.size.height / 2));
}
CGPoint superLoc = [self convertPoint:layerLoc toView:self.superview];
self.layer.anchorPoint = CGPointMake(anchorPointX, 0.5);
self.layer.position = superLoc;
}
- (CGFloat) pToA: (CGPoint) touchPoint {
CGPoint start;
if (_dotButtonIndex == kDotButtonFirst) {
start = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
} else {
start = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds));
}
return atan2(start.y - touchPoint.y, start.x - touchPoint.x);
}
Link to project on GitHub: Project Link
Figured it out.
I had to make it have an initial width so the angle would work.
_initialAngle = atan2(startPoint.y - endPoint.y, startPoint.x - (endPoint.x + self.frame.size.width));