How to drag a line in ios using UIPanGestureRecognizer - ios

I am writing a program where the user will drag a line from one UILabel to another. I created a UIView subclass called DragView, and overrode the drawRect method. I made the UIView a subview of the RootController view. The DragView is definitely visible, the drawRect method is definitely being called, but no line is visible.
These are (what I think are) the relevant pieces of code.
//DragView.m
- (void)drawRect:(CGRect)rect
{
if (context == nil)
{
context = UIGraphicsGetCurrentContext();
}
if (_drawLineFlag)
{
CGContextSetLineWidth(context,2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0,0.0,1.0,1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context,color);
CGContextMoveToPoint(context,_startX, _startY);
CGContextAddLineToPoint(context,_currentX,_currentY);
CGContextStrokePath(context);
}
}
DrawProgramAppDelegate
- (void) initializeUI
{
.....
dragView = [[DragView alloc] initWithFrame:CGRectMake(0.0f,0.0f,1024.0f,768.0f)] ;
[view addSubview: dragView];
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[dragView addGestureRecognizer:panGestureRecognizer];
.....
}
The event handler is:
- (void) handlePan:(UIPanGestureRecognizer *) recognizer
{
CGPoint point = [recognizer translationInView:dragView];
[dragView setCurrentX:point.x];
[dragView setCurrentY:point.y];
[dragView setDrawLineFlag:YES];
[view bringSubviewToFront:drawView];
[dragView drawRect:CGRectMake (0.0f,0.0f,768.0f, 1024.0f)];
}
Many thanks for your help.
Jon

It seems to me you are trying to draw a path (you should take a look at this post). Here it seems you just draw a line from the last point to the current point
CGContextMoveToPoint(context,_startX, _startY);
CGContextAddLineToPoint(context,_currentX,_currentY);
which given the frequency of the call would only draw a tiny line.
You should not call drawRect:
[dragView drawRect:CGRectMake (0.0f,0.0f,768.0f, 1024.0f)];
You should tell the system the view needs displaying
[dragView setNeedsDisplay];
Also you should check the gesture recognizer state, defined as
typedef enum {
UIGestureRecognizerStatePossible,
UIGestureRecognizerStateBegan,
UIGestureRecognizerStateChanged,
UIGestureRecognizerStateEnded,
UIGestureRecognizerStateCancelled,
UIGestureRecognizerStateFailed,
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
} UIGestureRecognizerState;
And possibly only draw if the state is UIGestureRecognizerStateChanged or UIGestureRecognizerStateEnded

Related

UIPinchGestureRecognizer in UIView is not working properly

I am trying to do zoom-in and zoom-out in a UIView using UIPinchGestureRecognizer. But when I do pinch on my trackpad, it is not recognising the pinch and the control is not going to my twoFingerPinch function. I am using the following code.
- (void)viewDidLoad {
//.......
UIPinchGestureRecognizer *twoFingerPinch = [[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(twoFingerPinch:)];
[myview addGestureRecognizer:twoFingerPinch];
//.....
}
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer
{
NSLog(#"Pinch scale: %f", recognizer.scale);
if (recognizer.scale >1.0f && recognizer.scale < 2.5f) {
CGAffineTransform transform = CGAffineTransformMakeScale(recognizer.scale, recognizer.scale//);
myview.transform = transform;
}
}
Why it is not recognising the pinch from trackpad? Is there any other method to do the same?
First click on the Option button. you will get 2 gray spots which you can move using the mouse or trackpad. in older versions you need to press shift+option.
for more details check this.
Make sure that userInteractionEnabled is set to yes for your myview,
myview.userInteractionEnabled = YES;

How to zoom an UIImageView

I'm rendering CGPDFPage in UIImageView but not zooming how we can zoom if any know plz let me know
PDFDocument = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfUrl);
totalPages = (int)CGPDFDocumentGetNumberOfPages(PDFDocument);
NSLog(#"total pages %i",totalPages);
//struct CGPDFPage *page =CGPDFDocumentGetPage(PDFDocument, 1);
CGFloat width = 600.0;
// Get the page
CGPDFPageRef myPageRef = CGPDFDocumentGetPage(PDFDocument, i);
// Changed this line for the line above which is a generic line
//CGPDFPageRef page = [self getPage:page_number];
CGRect pageRect = CGPDFPageGetBoxRect(myPageRef, kCGPDFMediaBox);
CGFloat pdfScale = width/pageRect.size.width;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// White BG
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
// ***********
// Next 3 lines makes the rotations so that the page look in the right direction
// ***********
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(myPageRef, kCGPDFMediaBox, pageRect, 0, true));
CGContextDrawPDFPage(context, myPageRef);
CGContextRestoreGState(context);
imageView= UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
You should add your imageView as subview of UIScrollView.
This SO answer describes how to zoom UIImageView inside UIScrollView:
Set your view controller up as a <UIScrollViewDelegate>
Draw your UIScrollView the size you want for the rectangle at the center of the view. Set the max zoom in the inspector to something bigger than 1. Like 4 or 10.
Right click on the scroll view and connect the delegate to your view controller.
Draw your UIImageView in the UIScrollView and set it up with whatever image you want. Make it the same size as the UIScrollView.
Ctrl + drag form you UIImageView to the .h of your View controller to create an IBOutlet for the UIImageView, call it something clever like imageView.
Add this code:
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
Run the app and pinch and pan til your heart's content.
Go with this
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.scrollView.minimumZoomScale=0.5;
self.scrollView.maximumZoomScale=6.0;
self.scrollView.contentSize=CGSizeMake(1280, 960);
self.scrollView.delegate=self;
}
Check Apple Documentation
Another way is to implement UITapGestureRecognizer in your viewController
- (void)viewDidLoad
{
[super viewDidLoad];
// target - what object is going to handle
// the gesture when it gets recognised
// the argument for tap: is the gesture that caused this message to be sent
UITapGestureRecognizer *tapOnce =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapOnce:)];
UITapGestureRecognizer *tapTwice =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapTwice:)];
tapOnce.numberOfTapsRequired = 1;
tapTwice.numberOfTapsRequired = 2;
//stops tapOnce from overriding tapTwice
[tapOnce requireGestureRecognizerToFail:tapTwice];
// then need to add the gesture recogniser to a view
// - this will be the view that recognises the gesture
[self.view addGestureRecognizer:tapOnce];
[self.view addGestureRecognizer:tapTwice];
}
Basically this code is saying that when a UITabGesture is registered in self.view the method tapOnce or tapTwice will be called in self depending on if its a single or double tap. You therefore need to add these tap methods to your UIViewController:
- (void)tapOnce:(UIGestureRecognizer *)gesture
{
//on a single tap, call zoomToRect in UIScrollView
[self.myScrollView zoomToRect:rectToZoomInTo animated:NO];
}
- (void)tapTwice:(UIGestureRecognizer *)gesture
{
//on a double tap, call zoomToRect in UIScrollView
[self.myScrollView zoomToRect:rectToZoomOutTo animated:NO];
}
Hope that helps

How to add a gesture recognizer to a shape drawn by uibezierpath

I am drawing a circle in the drawRect function in a subclass of UIView
- (void)drawRect:(CGRect)rect
{
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, 2.0);
CGContextSetRGBFillColor(contextRef, 0, 0, 1.0, 1.0);
CGContextSetRGBStrokeColor(contextRef, 0, 0, 1.0, 1.0);
CGRect circlePoint = (CGRectMake(self.bounds.size.width/3, self.bounds.size.height/2, 200.0, 200.0));
CGContextFillEllipseInRect(contextRef, circlePoint);
}
I want to add a gesture recognizer to the circle to make it tappable
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
I thought of dragging a UIGestureRecognizer onto the view (in storyboard) in the location where the big circle will be, but the circle is much bigger than the UIGestureRecognizer widget.
How can I either combine the code or assign a UIGestureRecognizer to an area of the view that's exactly the same as the size and location of the circle?
The short answer is that you can't. Gesture recognizers are attached to views, not shapes or layers. You would have to create a custom view object for each shape. You could certainly do that.
What I suggest you do is to create a custom subclass of UIView that manages all your shapes. (I'll call it ShapesView) Have that custom ShapesView manage an array of custom shape objects. Attach a gesture recognizer to your ShapesView. In the code that responds to gestures, have it do custom hit testing to determine which shape was tapped, and move the shapes around.
UIBezierPath includes a containsPoint method that would allow you to do hit testing if you maintained a bezier path for each shape.
I'm not sure how to do it using drawRect the way you are, but I've done something similar using UIBezierPath. I subclassed UIView, and made this view the main view of my controller. This is the code in that view,
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
self.shape = [UIBezierPath bezierPathWithOvalInRect:(CGRectMake(self.bounds.size.width/3, self.bounds.size.height/3, 200.0, 200.0))];
}
return self;
}
-(void)drawRect:(CGRect)rect {
[[UIColor blueColor] setFill];
[self.shape fill];
}
shape is a property declared in the .h file. In the view controller .m file, I add the gesture recognizer, and check if the touch is inside the shape,
#interface ViewController ()
#property (strong,nonatomic) RDView *mainView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mainView = (RDView *)self.view;
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
}
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper {
if ([self.mainView.shape containsPoint:[tapper locationInView:self.mainView]]) {
NSLog(#"tapped");
}
}

iOS: DrawRect does not move my view

I’m a new developer on iOS and I’m struggling with the DrawRect method: the first time it gets called, it actually draws what I want where I want, but all the next calls to DrawRect fail to move my view (although they do resize it).
I therefore made a minimalist test app to reproduce my problem but still could not isolate the cause.
This app just draws a blue rectangle in the top left corner, and each time you tap into it, it’s supposed to:
Switch width and height (this does work)
Move the rectangle by 10 points to the right (this does not work)
Of course I checked that DrawRect actually gets called and that its bounds did change to what I wanted, but still, my view does not want to move.
==============================================
Here’s my ViewController (RVTViewController.m)
==============================================
#implementation RVTViewController
(void)viewDidLoad`
{
[super viewDidLoad];
if (!self.myView)
{
CGRect viewBounds = CGRectMake(0,0,100,150);
self.myView = [[RVTView alloc] initWithFrame:viewBounds];
[self.view addSubview:self.myView];
UITapGestureRecognizer* gestRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[self.myView addGestureRecognizer:gestRec];
}
}
-(void) tap:(UITapGestureRecognizer*) gesture
{
CGRect newViewBounds = CGRectMake(self.myView.bounds.origin.x + 10,
self.myView.bounds.origin.y,
self.myView.bounds.size.height,
self.myView.bounds.size.width);
self.myView.bounds = newViewBounds;
[self.myView setNeedsLayout];
[self.myView setNeedsDisplay];
}
#end
=====================================
And here’s my custom view (RVTView.m)
=====================================
#implementation RVTView
- (void)drawRect:(CGRect)rect
{
CGRect newBounds = self.bounds;
UIBezierPath* newRect = [UIBezierPath bezierPathWithRect:newBounds];
[[UIColor blueColor] setFill];
UIRectFill(self.bounds);
[newRect stroke];
}
#end
Can someone please tell me what I am getting wrong ?
Using [self.myView setFrame:newViewBounds]; instead of self.myView.bounds = newViewBounds; fixed the problem.

Lines drawn using drawRect method not getting scrolled

I am creating an app where I want to draw lines on scrollView. I am able to draw lines.
Here is my code
#interface GraphOnScrollView : UIScrollView
#property(strong,nonatomic)NSMutableArray *intensityArray;
#end
import "GraphOnScrollView.h"
#implementation GraphOnScrollView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.userInteractionEnabled=YES;
self.scrollEnabled=YES;
UIButton *DirectMsgBtn1 =[UIButton buttonWithType:UIButtonTypeCustom];
DirectMsgBtn1.titleLabel.font =[UIFont systemFontOfSize:12.0];
[DirectMsgBtn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[DirectMsgBtn1 setTitle:#"direct message" forState:UIControlStateNormal];
[DirectMsgBtn1 setBackgroundColor:[UIColor clearColor]];
[DirectMsgBtn1 addTarget:self
action:#selector(DirectMessageViewPopUp:)
forControlEvents:UIControlEventTouchDown];
DirectMsgBtn1.frame = CGRectMake(0.0, 0, 100, 30);
[self addSubview:DirectMsgBtn1];
DirectMsgBtn1 = nil;
}
return self; }
// Only override drawRect: if you perform custom drawing. // An
empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
CGFloat y_Axix =20.0;
CGFloat lineWidth=1.0;
for (int i=0; i<[self.intensityArray count]; i++)
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 2.0);
lineWidth+=1;
CGFloat red[4] = {1.0f, 0.5f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGFloat width=[[self.intensityArray objectAtIndex:i] floatValue];
CGContextMoveToPoint(c, 5.0f, y_Axix);
CGContextAddLineToPoint(c, width, y_Axix);
CGContextStrokePath(c);
CGContextAddArc(c,width,y_Axix,1.0f,0,2*3.1415926535898,1);
CGContextDrawPath(c,kCGPathStroke);
y_Axix=y_Axix+50;
}
NSLog(#"intensity array %#", self.intensityArray);
self.contentSize = CGSizeMake(self.frame.size.width, 1000);
}
This is code I am using for adding scrollview on my view
GraphOnScrollView *GraphView =[[GraphOnScrollView
alloc]initWithFrame:CGRectMake(0.0, 150.0, 320.0, 280.0)];
GraphView.backgroundColor =[UIColor whiteColor];
GraphView.intensityArray =[NSMutableArray arrayWithObjects:#"60",#"100",#"40",#"10",#"20",#"40",#"40",#"100",
nil];
[self.view addSubview:GraphView];
Using this code the lines which i have drawn is not getting scrolled but the scrollview is scrolled. I don't know what is the problem.
Thanks
While drawing on any view it draws everything on the canvas of that view.
In the case of your, you are drawing on UIScrollView so all drawing performs on the canvas of the UIScrollView, so it is not scrollable.
To solve that problem you can create on separate UIView with the size you want, perform any drawing on it and add that view in scrollview. I think this will be the best solution.
You can also refer to this link for some more help.
Alternate Approach (i actually used uiview for drawing and made it look like scroll)
save the touch location in
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
record the touch point in touches moved.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
now you can translate coordinate of your points as
newX=x+(touchstart.x-touchMoved.x);//do this for x of every point
newy=y+(touchstart.y-touchMoved.y);// do this for y of every point
put the above lines in a function and call them from touches moved you can do it in touches ended method as well if lag is ok with you.
Point is translate the point and calculate the degree of translation from user touch began and moved or swipe

Resources