MKAnnotationView disappearing on swipe and double-tap zoom - iphone

I have subclassed MKAnnotationView to create an annotation that basically draws a circle around a point on a map view through override of drawRect. The circle draws fine in the following situations (in the simulator):
On initial load of the map view
On swipe, but only when swipe motion is stopped before touch ends (so that map doesn't "coast" after touch ends)
On pinch zoom
The circle will disappear when any of the following actions occur:
Swipe where map "coasts" after touch ends
Double-tap zoom
The circle will reappear if any of the actions in the "working" group are taken after it has disappeared.
What might cause this? I'm not a draw/display/layout expert (frankly, I'm not an obj C or iPhone expert either).
Here is some slightly simplified code that seems most relevant from my MKAnnotationView subclass:
- (void)drawRect:(CGRect)rect {
// Drawing code
[self drawCircleAtPoint:CGPointMake(0,0) withRadius:self.radiusInPixels andColor:self.circleAnnotation.color];
}
- (void)drawCircleAtPoint:(CGPoint)p withRadius:(int)r {
CGContextRef contextRef = UIGraphicsGetCurrentContext();
float alpha = 0.75;
CGContextSetRGBFillColor(contextRef, 255, 0, 0, alpha);
CGContextSetRGBStrokeColor(contextRef, 255, 0, 0, alpha);
// Draw a circle (border only)
CGContextStrokeEllipseInRect(contextRef, CGRectMake(0, 0, 2*r, 2*r));
}

Did you add this method?
- (void)setAnnotation:(id <MKAnnotation>)annotation
{
[super setAnnotation:annotation];
[self setNeedsDisplay];
}
This is taken from Apple's sample code app called WeatherMap which was removed from Apple Developer Center, but can be found on github
https://github.com/acekiller/iOS-Samples/blob/master/WeatherMap/Classes/WeatherAnnotationView.m

Related

Allowing touch to pass through transparent images

I'm using a piece of code I found to pass touch events through transparent parts of a UIImageView. I'm subclassing UIImageView and adding this:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 1, NULL,
kCGImageAlphaOnly);
UIGraphicsPushContext(context);
[self.image drawAtPoint:CGPointMake(-point.x, -point.y)];
UIGraphicsPopContext();
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;
if(transparent){
return NO;
} else {
return YES;
}
}
So far its working great in my iPad version. However, in my iPhone version, I set the image frames to be half of the image's actual size (self.image.frame.size.width/2). This code is interfering with my pan gestures in an odd way, where if I touch the top left of the image I cannot access my pan gesture, but I can access it to the far bottom right, past the actual image into a transparent zone.
Removing the code returns the pan gesture to normal. However, I would still like to keep the ability to ignore touches on transparent parts. Does anyone know what part of this code is messing with my touch points or any other reason its acting like this?
Thanks
I know this question is very old, but I just had to use this on a project and my problem was that I was setting the imageView frame manually. What helped was changing the code so resizing was only done through transforms.
If the imageView is initially the same size as the image inside it, you can use this code and it will work with any transform applied to the imageView afterwards.
So in your iPhone version, you could set the frame of the imageView to the size of the image inside it and then apply a scaling transform to it so it's half the size.

CGContextStrokePath not working when zooming and drawing images

I'm drawing lines according to touchesMoved: method and normally it works fine. But when I zoom into the image and draw, the previously drawn lines are both displaced and keep getting more and more blurry, ultimately vanishing. I've tried using UIPinchGestureRecognizer and simply increasing the frame of myImageView (for multi-touch events only) but the problem occurs both ways. Here's the code for drawing:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if(count==1){//single touch case for drawing line
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:myImageView];
UIGraphicsBeginImageContext(myImageView.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, myImageView.frame.size.width, myImageView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
else{//multi touch case
// handle pinch/zoom
}
}
Here is the image drawn over without zooming:
And this is the image depicting the problem after zooming-in with the red arrow showing the segment that was already drawn before zooming-in (as shown in previous image). The image is both blurred and displaced:
It can also be noticed that a part of the line drawn towards the end is unaffected and the phenomenon occurs for lines drawn back in time. I believe the reason for this is that the image size attributes are being lost when I zoom in/out which probably causes the blur and shift, but I'm not sure about that!
EDIT- I've uploaded a short video to show what's happening. It's sort of entertaining...
EDIT 2- Here's a sample single-view app focussing on the problem.
I downloaded your project and I found the problem is of autoresizing. The following steps will solve it:
Step 1. Comment the line 70:
drawImage.frame = CGRectMake(0, 0, labOrderImgView.frame.size.width, labOrderImgView.frame.size.height);
in your touchesMoved method.
Step 2. Add one line of code after drawImage is alloced (line 90) in viewDidLoad method:
drawImage.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Then, the bug is fixed.
You are always just drawing to an image context the size of your image view - this of course gets blurry, as you do not adapt to a higher resolution when zoomed in. It would be more sensible to instead create a UIBezierPath once and just add a line to it (with addLineToPoint:) in the touchesMoved method, then draw it in a custom drawRect method via [bezierPath stroke]. You could also just add a CAShapeLayer as a subview of the image view and set its path property to the CGPath property of the bezierPath you created earlier.
See Drawing bezier curves with my finger in iOS? for an example.
I implemented behavior like this in next way:
You should remember all coordinates of your path (MODEL).
Draw your path into temporary subview of imageView.
When user starts pinch/zoom your image - do nothing, i.e path will be scaled by iOS
In the moment when user has finished pinch zooming - redraw your path in correct way using your model.
If you save path as image you get bad looking scaling as result.
Also - do not draw path straight to image - draw to some transparent view and split them together at the end of editing.

Create and Rotate a Rectangle using Draw method iPhone?

i am working on a cocos2d project in which i draw a rectangle with the help of draw method as following
-(void)draw
{
glEnable(GL_LINE_SMOOTH);
glColor4ub(255, 255, 255, 255);
glLineWidth(2);
CGPoint verticesAll[] = { vertices1, vertices2,vertices3, vertices4 };
ccDrawPoly(verticesAll, 4, YES);
}
now i need to rotate the rectangle when user moves his finger on screen. how can i change all the four cordinates so as to rotate the rectangle according to touches moved .
if i calculate the angle from the center of the screen to one of the axis of rectangle and then accordingly change that particular coordinate but the change in other coordinates won't be the same so how can i achieve that?
vertices1,2,3.. are cgpoints
also on a ccmenu click i need to draw more rectangle .. i am not sure how to call draw method to create more rectangles with different vertices??
If you are using Cocos2D and are subclassing CCNode, then you can just use a CCAction on the object.
For example:
#interface MySquare : CCNode
#end
#implementation MySquare
- (void)draw
{
// your drawing code
}
#end
MySquare *square = [[MySquare alloc] init];
[square runAction:[CCRotateBy actionWithDuration:0.25f angle:360.0f]];

how to draw new lines without old ones disappering?

I want to create a simple tool for drawing. The purpose is to draw a line that follows the accelerometer of the iPhone & iPad, so if the user tilts the device a line will be draw in the direction the device was moved.
I am able to register acceleration and drawing lines. My problem is that as soon as I draw a line the old one disappears. One possible solution would be to save to points already drawn and then re-draw everything, but I would think there are better solutions?
All help is appreciated!
My drawRect is at the moment like this:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 20.0);
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
}
A different method is responsible for refreshing. This method is also called from the uiviewcontroller with certain intervals. Right now it shows a "trail" (or what I should call it) in the direction the device was moved. Not exactly what I am looking for:
- (void)drawNewLine:(CGPoint)to {
// calculate trail behind current point
float pointDifferenceX = ((toPoint.x - to.x) * 9);
float pointDifferenceY = ((toPoint.y - to.y) * 9);
fromPoint = CGPointMake(toPoint.x + pointDifferenceX, toPoint.y + pointDifferenceY);
toPoint = to;
[self setNeedsDisplay];
}
I can think of two options:
Either save all points and redraw the lines whenever the screen needs to be refreshed (as you mentioned)
Draw the lines into an off-screen pixelmap and refresh the screen from there
In either case, respect the Hollywood principle: Don't call, you will be called. That means don't just draw to the screen but wait for until drawRect: of your UIView is called. (You can trigger this by calling setNeedsDisplay.)

DrawRect of UIView inside UIScrollView

I'm trying to draw a small image on a UIScrollView for my iPhone app. I started with a UIImage created from a png I included in my bundle and that works ok. Every time the zooming/panning stops the delegate of the scrollview recalculates the frame of that UIImage (which is a subview of the UIScrollView's contentView) and calls setNeedsDisplay. The frame gets smaller and smaller in width/height measurements as you zoom into the scrollview because I want the image to stay the same size on the screen. While the user is zooming the image is the wrong size but as soon as the zooming stops it gets corrected. Not great but not the worst thing either.
The problem is now that I want to draw the image myself rather than have a static png. I've subclassed UIView and got into the drawRect method but I can't get the maths right to draw a smooth looking path when the view is zoomed in. I thought I could just scale the line width down and the radius of the circle I'm drawing (CGContextAddArc) but it looks as if the iPhone has tried to draw a thin lined circle over two or three pixels and then enlarged those pixels, rather than zoomed the view in and drawn a highly accurate circle over it.
This is the ViewController resizing the UIView (which is a subview of the UIScrollView's contentView)
float scaler = (1/scrollView.zoomScale);
[targetView setFrame:CGRectMake(viewCoords.x-11*scaler, viewCoords.y-11*scaler, 22*scaler,22*scaler)];
[targetView setNeedsDisplay];
This is the drawRect of the UIView
float x = rect.origin.x + rect.size.width/2.0;
float y = rect.origin.y + rect.size.height/2.0;
float radius = (rect.size.width-2.0*lineWidth)/2.0;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx,lineWidth );
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextAddArc(ctx, x, y, radius , 0, 2* M_PI, 1);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
I'm open to the idea of placing the UIView subclass elsewhere, but I must have it move in sync with the UIScrollView's contentview
See my answer to this question. The UIScrollView applies a transform to your content view when it does the pinch zooming, which is what's causing your blurriness. You can override this to draw your own content sharply if you follow the method I describe.