0
votes

Using CGContext, drawing a dashed line starting with a painted segment is easy:

using (var ctx = UIGraphics.GetCurrentContext())
{
    ctx.BeginPath();
    //... draw a path here
    var pattern = new float[] { 2, 2 };
    ctx.SetLineDash(0, pattern);
    ctx.DrawPath(CGPathDrawingMode.Stroke);
}

This draws a line looking like this "xx--xx--xx--xx--", where "x" means painted, and "-" means not painted.

Now I want to draw a line starting with an unpainted segment, that is: "--xx--xx--xx--xx". Is there an elegant way to achieve this? E.g. by telling iOS to start with an unpainted segment?

Given our example, a line starting with unpainted segments can be achieved using the phase parameter:

using (var ctx = UIGraphics.GetCurrentContext())
{
    ctx.BeginPath();
    //... draw a path here
    var pattern = new float[] { 2, 2 };
    ctx.SetLineDash(2, pattern);
    ctx.DrawPath(CGPathDrawingMode.Stroke);
}

However, for more complex patterns (something like { 2, 4, 3, 7, 5, 6 }) using the phase parameter becomes more cumbersome. The pattern probably needs to be shifted in addition to the phase parameter.

To wrap up: Is it possible to elegantly create a line dash starting with an unpainted segment, without using the phase parameter?

Note: The code examples are written in C# (MonoTouch), but the question applies to native iOS code as well.

1
a clunky workaround may be to draw a solid line with the desired color and then draw a dashed white (or backgroundcolor) line on top of it.user2320861
@user2320861 Thank you, the suggestion should work well in case the background color is known. In my case, I need to be able to draw the line above diverse backgrounds (even images and the like). So I really need unpainted segments, not "painted over" segments.Stephan Palmer

1 Answers

0
votes

Simple solution

Using only the line dash feature, the given problem cannot be solved without the phase parameter. It can be solved by re-ordering the dash array, and setting a phase.

To start with an unpainted segment, move the last dash array entry to the front, and set a phase with the same value. E.g. when the pattern -xx-xx-xx-xx-xx... is desired, the dash array 1, 2 with phase 0 would lead to a pattern like x--x--x--x--.... The dash array 2, 1 with phase 2 would lead to the pattern -xx-xx-xx-xx-xx..., as desired.

Extended solution with adapted pattern repeating

It seems iOS always alternates between painted and unpainted segments, and does not reset when the dash array is repeated. So e.g. the dash array 1, 2, 1 would result in a line pattern looking like x--x-xx-x--x.... In our case, we wanted the whole pattern to repeat. That is, with the given dash array, the line pattern should look like x--xx--xx--xx....

To achieve that, we need to ensure that the dash array always has an even number of elements. In addition to re-ordering the dash array and setting a phase, we need to adapt and remove elements. There are four cases to consider.

1. Start with painted segment, even number of segments.

Nothing to do here. Use dash array as is. Phase is 0.

2. Start with unpainted segment, even number of segments.

Move the last dash array entry to the front, and set a phase with the same value. Refer to the simple example above.

3. Start with painted segment, odd number of segments.

Add the last dash array entry to the first entry. Remove the last entry. Set a phase equal to the original last dash array entry.

E.g. the dash array 1, 2, 1 would normally lead to a pattern x--x-xx-.... The dash array 2, 2 with a phase of 1 leads to the desired pattern x--xx--xx--....

4. Start with unpainted segment, odd number of segments.

Add the first dash array entry to the last entry. Remove the first entry. Set a phase equal to the sum of all entries minus the original first dash array entry (this essentially lets the pattern start near the end, exactly where we added the original first entry to the last entry).

E.g. the dash array 1, 2, 1 would normally lead to a pattern x--x-xx-.... The pattern 2, 2 with a phase of 3 leads to the desired pattern -xx--xx--xx....

Alternatives

An alternative which does not use line dash feature could be the one described by @user2320861. @user2320861 suggests to paint over a solid line with a patterned line, using the background color. This should work well when the background color is known, and a uniform background is used.

A variant for diverse backgrounds (e.g. images) could be to set a clipping mask (CGContextClipToMask) by drawing a patterned line. Then a solid line could be drawn with this clipping mask.