How would you go about animating the drawing of a line in a UIView on the iPhone? Is this possible? It can be drawn but can it easily be animated so it appears to be hand drawn?
There's no built-in way to do this no. You'd have to redraw the line repeatedly, interpolating between the start and end points using a timer callback to invalidate the view and trigger a redraw. Of course the redraw would have to draw everything in the area of the view bring redrawn which is potentially slow.
What I would do if I had a series of lines I wanted to draw over a period of time is to have two subviews - they would cover the same area and the top one would have a transparent background. Have the top one draw just the line that I am currently animating and when it's finished, draw the full length of it in the lower view. Then repeat, animating the next line in the top view.
With the new API you can do that easily, using strokeEnd property of CGPath.
You can read more details here: What's the easiest way to animate a line?
Related
I am creating an app for practice that is a simple drawing app. The user drags his/her finger along the screen and it colors in a 100px x 100px square.
I currently achieve this by creating a new colored UIView where the user taps, and that is working. But, after a little time coloring in, there is substantial lag, which I believe is down to there being too many UIViews as a subview of the main view.
How can I, and others who similarly create UIViews on dragging a finger reduce the lag to none at all, no matter how many UIViews there are. I also think that perhaps this is an impossible task, so how else can someone like me color a cube of the size stated above in the main view on a finger dragged along the screen?
I know that this may seem like a specific question, but I believe that it could help others understand how to reduce lag if there are a very large amount of UIViews where a less performance reducing option is available.
One approach is to draw each square into an image and display that image, rather than keeping around an UIView for each square.
If your drawing is simple enough, though, you can use OpenGL to do this, which is much faster. You should look at Apple's GL Paint Sample Code which shows how to do this in OpenGL.
If your drawing is too complex for OpenGL, you could create, for example, a CGBitmapContext, and draw each square into that context when the user drags their finger. Whenever you draw a new square into that bitmap, you can turn the bitmap into an image (via CGBitmapConxtextCreateImage) and display that image an a UIImageView.
There are two things that come to my mind:
1- Use Instruments tool to check if you are leaking any memory
2- If you are just coloring the views than instead of creating images for each of them, either set the background color property of UIView or override the drawRect method to do custom drawing
I think what you are looking for is the drawRect: method of UIView. You could create your custom UIView (you propably have that already) and override the drawRect method and do your drawing there! You will have to save your drawings in an array or another container and call the setNeedsDisplay method whenever the array content is changed.
Attached 1 is a screenshot from an app called GeniusScan where you can photograph any document and an adjustable rectangular grid shows on the imageview. You can easily adjust the borders of the grid with your fingers to select the portion of the image that you want to scan. It will be then transformed into the correct prospective.
1- How can I draw and interact with the grid on the imageview?
2- How can I return the corner points of the grid to my view controller.
Update: I found a wonderful class called BJImageCropper which allows to use fingers to ajust the borders, but only for a box like rectangle. Can anyone suggest how it can be updated to support shapes like in the GeniusScan app?
Dude:
I created a demo that solves both questions:
1- How can I draw and interact with the grid on the imageview?
By Adding 4 views that will act as interactive control points by adding UIPanGestureRecognizer and then drawing the grid using CAShapeLayer on top of your view.
2- How can I return the corner points of the grid to my view controller.
You must keep references to the four control points of your grid.
Here's the link to my code.
This isn't actually drawing on top of UIImageView. It's actually an overlay (view) on top of the UIImageView. You need to keep track of 4 points (have 4 views as subview of the layer), track their positions, once moved, use drawRect: to draw lines based on the 4 points.
The way I've implemented it in my app is, I overlay the UIImageView with a transparent 'SelectionView' (a custom view that I wrote). The selectionView contains 4 custom subview of class 'Vertex'. The vertex talk back to the selectionView via protocol method every time user touches/moves it (it's actually not important which vertex moved, just that it moved):
- (void)vertexMoved:(Vertex *)vertex;
Then the selectionView knows that it needs to re-draw, so it calls setNeedsDisplay which calls internally calls drawRect (you should never call drawRect) where I do the actual drawing of the bounding rect. Basically, iterate through each vertex and draw a line using Quartz APIs and fill it with semi transparent/hollow color.
This is how I am doing it atleast, I am sure there are other ways.
I have a UIView that allows the user to draw a line (myLine) on the screen. This UIView is directly above another UIView that has several shapes drawn with CGPaths. When the user taps on one of these shapes I need to erase any portion of myLine that is above one of these other shapes as if I was erasing the pixels with an eraser.
What would be the best way to approach this?
I need the light blue part of the line to be erased leaving the dark blue portion
1) (current approach partially works) I'm able to use the path shape from the bottom view as a mask in the top view but it is only masking the UIView. If I later need to change the mask location the vector strokes are still there. (I know this is because all off my lines are being redrawn in the drawrect of the view)
2) After I draw each line should I somehow cache the drawing as an image and THEN
slice out the parts inside the triangle?
3)Is there a better approach to this?
This link provided the answer:
Building a Simple Drawing App
I cache the drawing to a bitmap context and then clip out
the unneeded parts of the bitmap.
I want to create a simple application which performs some calculations and then draws some images on view. I use NSBezierPath. Then I must resize the view and allow people scroll the finished picture. But i don't know how.If I also try to draw an image on an invisible part of canvas then it becomes invisible or isn't drawn (I couldn't know the future canvas size).
Check out the Apple sample code called BezierPathLab. I think that will get you started. There's lot of other sample code for Quartz 2D drawing too.
Being able to scroll and resize the view should be as simple as putting the view that you will be using to draw inside an NSScrollView.
I have an MKOverlayView that displays animated radar data as a series of images. The issue I have is that the radar images are chopped into tiles by MapKit. To swap images I have a timer that calls an update function which sets the current image in my overlay and then calls the following
[myRadarOverlayView setNeedsDisplayInMapRect:self.mapView.visibleMapRect];
The overlay updates, but does so one tile at a time so I get a choppy animation. Any ideas about how make all the tiles animate (i.e. swap images) at the exact same time?
I solved this by adding a UIImageView as a subview of the MKOverlayView.
To animate, stop drawing with the
normal
drawMapRect:zoomScale:inContext: (via
an instance variable/property flag) and
draw to the UIImageView instead (to
the animationImages property), then
use startAnimating.
You can handle panning and zooming by
reinitializing the UIImageView in
response to
mapView:regionDidChangeAnimated:.
Sample code how to animate a circle:
http://yickhong-ios.blogspot.com/2012/04/animated-circle-on-mkmapview.html
Is there a callback when all the tiles have finished loading? If so, you could go with double buffering, and update the view offscreen, and then switch it in.