Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best approach to draw lines between views?

Background: I have a custom scrollview (subclassed) that has uiimageviews on it that are draggable, based on the drags I need to draw some lines dynamically in a subview of the uiscrollview. (Note I need them in a subview as at a later point i need to change the opacity of the view.)

So before I spend ages developing the code (i'm a newbie so it will take me a while) I looked into what i need to do and found some possible ways. Just wondering what the right way to do this.

  1. Create a subclass of UIView and use the drawRect method to draw the line i need (but unsure how to make it dynamically read in the values)
  2. On the subview use CALayers and draw on there
  3. Create a draw line method using CGContext functions
  4. Something else?

Cheers for the help

like image 224
sregorcinimod Avatar asked May 01 '11 10:05

sregorcinimod


People also ask

How can I draw a line in Microsoft Word?

On the Insert tab, in the Illustrations group, click Shapes. Under Lines, click any line style you like. Click one location in the document, hold and drag your pointer to a different location, and then release the mouse button.

How do you draw a line in Python?

line() Draws a line between the coordinates in the xy list. Parameters: xy – Sequence of either 2-tuples like [(x, y), (x, y), …] or numeric values like [x, y, x, y, …].


1 Answers

Conceptually all your propositions are similar. All of them would lead to the following steps (some of them done invisibly by UIKit):

  1. Setup a bitmap context in memory.
  2. Use Core Graphics to draw the line into the bitmap.
  3. Copy this bitmap to a GPU buffer (a texture).
  4. Compose the layer (view) hierarchy using the GPU.

The expensive part of the above steps are the first three points. They lead to repeated memory allocation, memory copying, and CPU/GPU communication. On the other hand, what you really want to do is lightweight: Draw a line, probably animating start/end points, width, color, alpha, ...

There's an easy way to do this, completely avoiding the described overhead: Use a CALayer for your line, but instead of redrawing the contents on the CPU just fill it completely with the line's color (setting its backgroundColor property to the line's color. Then modify the layer's properties for position, bounds, transform, to make the CALayer cover the exact area of your line.

Of course, this approach can only draw straight lines. But it can also be modified to draw complex visual effects by setting the contents property to an image. You could, for example have fuzzy edges of a glow effect on the line, using this technique.

Though this technique has its limitations, I used it quite often in different apps on the iPhone as well as on the Mac. It always had dramatically superior performance than the core graphics based drawing.

Edit: Code to calculate layer properties:

void setLayerToLineFromAToB(CALayer *layer, CGPoint a, CGPoint b, CGFloat lineWidth)
{
    CGPoint center = { 0.5 * (a.x + b.x), 0.5 * (a.y + b.y) };
    CGFloat length = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    CGFloat angle = atan2(a.y - b.y, a.x - b.x);

    layer.position = center;
    layer.bounds = (CGRect) { {0, 0}, { length + lineWidth, lineWidth } };
    layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
}

2nd Edit: Here's a simple test project which shows the dramatical difference in performance between Core Graphics and Core Animation based rendering.

3rd Edit: The results are quite impressive: Rendering 30 draggable views, each connected to each other (resulting in 435 lines) renders smoothly at 60Hz on an iPad 2 using Core Animation. When using the classic approach, the framerate drops to 5 Hz and memory warnings eventually appear.

Performance comparison Core Graphics vs. Core Animation

like image 186
Nikolai Ruhe Avatar answered Oct 02 '22 01:10

Nikolai Ruhe