I know you can use a text field to display output but there is a limit on the size of the box. I can I display a message to the screen, without using text field? I'm not really finding anything useful so far in a couple books.
I think you can do this using,
CGContextSetStrokeColorWithColor(context, strokeColor);
CGContextSetFillColorWithColor(context, strokeColor);
CGContextSelectFont(context, "Helvetica", fontSize, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetTextPosition(context, 0.0f, round(fontSize / 4.0f));
CGContextShowText(context, [text UTF8String], strlen([text UTF8String]));
Related
In iOS7 CGContextSelectFont is deprecated. Deprecation message says that I have to use Core Text, but I don't know which is the exact equivalent of this piece of code:
CGContextSelectFont(context, "Helvetica", kBarLabelSize, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1.0);
CGContextSetTextMatrix (context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0));
CGContextShowTextAtPoint(context, barX, barY, [#"Some text" cStringUsingEncoding:NSUTF8StringEncoding], [barValue length]);
I've been able to create the font with this code:
CFMutableAttributedStringRef attrStr = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica"), kBarLabelSize, NULL);
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTFontAttributeName, font);
But now haw can I "draw" a text with this font into the context?
As best I can understand from your code, the exact equivalent is:
CGContextSetTextDrawingMode(context, kCGTextFill); // This is the default
[[UIColor blackColor] setFill]; // This is the default
[#"Some text" drawAtPoint:CGPointMake(barX, barY)
withAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica"
size:kBarLabelSize]
}];
Note that your calls to CGContextSetTextDrawingMode and CGContextSetRGBFillColor are setting the values to the defaults. Your call to CGContextSetTextMatrix is not needed when using UIKit drawing like this.
I have no idea what [barValue length] is here, however. I'm assuming that you simply incorrectly used this for the length of #"Some text". (length is not the number of bytes which is what you need. What you probably meant was [barValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]).
Note that UIKit string drawing (seen here) wraps Core Text.
I have found, at least in my case, the problem with the new NSString.drawAtPoint interface is that it may draw upside down, depending on how you are using the context.
An alternate is to use the Core Text methods, specifically the CTLine interface thusly:
NSDictionary *attribs = #{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:14.0]};
NSAttributedString *fontStr = [[NSAttributedString alloc] initWithString:#"some text" attributes:attribs];
CTLineRef displayLine = CTLineCreateWithAttributedString( (__bridge CFAttributedStringRef)fontStr );
CGContextSetTextPosition( ctx, xPosition, yPosition );
CTLineDraw( displayLine, ctx );
CFRelease( displayLine );
You probably can use the following to replace it.
CGContextSetFont
CGContextSetFontSize
So, I need to draw a series of dotted lines along an axis.
In the drawRect method I call another method to draw the axis..
In that method I save the GState draw the axis and then save the gstate again draw the dotted line when appropriate,then stroke the path restore the gstate add some thing to the axis fill the path..
The thing is now the whole thing is dotted ...
It seems the the code didn't discard the dotted line pattern when I restored the gstate ...
CGContextSaveGState(ctx);
CGContextSetFillColorWithColor(ctx, [[UIColor whiteColor] CGColor]);
.......
//draw a dased line
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx, 1.0);
CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGFloat const kDashedLinesLength[] = {1.0f, 0.5f};
CGContextSetLineDash(ctx, 0.0, kDashedLinesLength, 2);
CGContextMoveToPoint(ctx, LEFT_EXCLUSION_LENGTH + AXIS_LINE_WIDTH, crtYval);
CGContextAddLineToPoint(ctx, LEFT_EXCLUSION_LENGTH + AXIS_LINE_WIDTH + self.xAxis.visibleLength , crtYval);
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
...
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
How can I make sore that only the line I need gets doted ???
I'm not sure what's wrong with your code, but it's not a bug in the context restore which works fine. Likely you have another error in the code you replaced with .....
Could be that you have unbalanced save and restores which will cause all kinds of problems - I'd check that first.
I copied and pasted it with minimal changes into a small iOS test app custom view's drawRect method and ran it and I'm seeing what I expect.
here's the little test code that works as expected:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextSetFillColorWithColor(ctx, [[UIColor blackColor] CGColor]);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextSetLineWidth(ctx, 2.0);
//draw a dased line
CGContextSaveGState(ctx);
CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
CGFloat const kDashedLinesLength[] = {1.0f, 2.0f};
CGContextSetLineDash(ctx, 0.0, kDashedLinesLength, 2);
CGContextMoveToPoint(ctx, 100, 100 );
CGContextAddLineToPoint(ctx, 100, 200);
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
CGContextMoveToPoint(ctx, 200, 100 );
CGContextAddLineToPoint(ctx, 200, 200);
CGContextStrokePath(ctx);
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
}
And is the sample output:
You need to be careful to always exactly balance a Save with a Restore. I've had situations where I had one or the other too many in a totally different location of my app. Because iOS partially reuses contexts this can leave a graphics context in a weird state.
You should search your source code for all instances of a Save and a Restore and count if there are equal numbers of them.
I think I know your problem. Look at it this way: The line isn't drawn until you stroke the path. So whatever pattern is in effect when you call CGContextAddLineToPoint (for example) doesn't matter. When you call CGContextAddLineToPoint you're not drawing a line, you are simply building a path. I'm guessing that your subroutine for drawing the axes does not stroke them. The axes don't get drawn until you later call CGContextStrokePath, at which point the dashed pattern is in effect.
I am new to Objective-C and iOS development. I have a view with some figures drawn by core drawing. Now I want to fill those shapes with color and I don't know the path or context of shape. Does Objective-C have any function like flood-fill or put-pixel so that by having only the stroke color I can fill any shape inside my view.
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 50, 0);
CGContextAddLineToPoint(context, 0,320);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetRGBFillColor(context, 0, 255, 0, 1.0);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
This will make a circle and a square with some common region. I want a particular region to fill with color when a user taps that region.
So you are looking for flood fill in Objective C.
This is my implementation of Scan Line Flood Fill Algorithm.
Github : UIImageScanlineFloodfill
If you want to learn basic of flood fill:
Lode's Computer Graphics Tutorial Flood Fill
I hope this will help you.
Put your drawing code in the question and I can give you a specific answer.
Normally you just need to set a fill color using
[[UIColor redColor] setFill];
And any shapes you draw your core graphics will be filled with that color automatically.
Try this command:-
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
Core Graphics is closely tied to UIView and its drawRect: method and has a C interface. As you point out, you always draw in the current graphics context. I can think of 2 approaches: (1) When the user taps myView, set a property like myView.pointTapped, and in drawRect: find the shape to fill, set a fill color, and fill the closed path using GGGeometry methods.
There is an objective-C alternative: (2) Take a look at UIBezierPath. It's not as comprehensive as drawing in Core Graphics but it can be used in your ViewController implementation.
As you can see in the code below I do some transformations on my UIView before writing some text. It seems though that the position of the text is affected by the aforementioned transformations.
Is there any way to 'pop' these displacements so I can then write my text in relation to the original 0,0 coordinate?
//turn PDF upsidedown
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(100, aUIView.bounds.size.height+300);
transform = CGAffineTransformScale(transform, 0.5, -0.5);
CGContextConcatCTM(pdfContext, transform);
// Draw view into PDF
// Is renderInContext deprecated? Something to look into.
[aUIView.layer renderInContext:pdfContext];
CGContextSelectFont (pdfContext, "Helvetica", 14, kCGEncodingMacRoman);
CGContextSetTextDrawingMode (pdfContext, kCGTextFill);
CGContextSetRGBFillColor (pdfContext, 0, 0, 0, 1);
CGContextSetTextMatrix(pdfContext, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));
const char *text = "THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG TEST 1";
CGContextShowTextAtPoint (pdfContext, 10.0, 10.0, text, strlen(text));
I think CGContextSaveGState(cntx) and CGContextRestoreGState(cntx) are what you are looking for.
i have recorded each point when user touch begin move end the ipad,and then i add these points in to a CGMutablePathRef called path, then i use following code to draw the lines(path) user touched in ipad.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetStrokeColorWithColor(context, [UIColor redColor]);
CGContextSetLineWidth(context, 2);
CGContextAddPath(context, path);
CGContextStrokePath(context);
but these lines didn't look smooth, thanks for your help
You may achieve more smoothness by using the following:
UIGraphicsBeginImageContext(self.frame.size);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineJoin(UIGraphicsGetCurrentContext(), kCGLineJoinRound);
CGContextSetAllowsAntialiasing(UIGraphicsGetCurrentContext(), YES);
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), YES);
CGContextSetMiterLimit(UIGraphicsGetCurrentContext(), 2.0);
But if you need to draw very smooth lines/curves, then you need to redraw lines by using UIBezierCurve or any other curving algorithms.
Edit: I did some changes in my code for smooth drawing. Check my classic board app: https://itunes.apple.com/app/id493525167
You will need to add this just after you first line.
CGContextSetAllowsAntialiasing(context, true);
I'd suggest you to use Cocos2d for perfectly smooth lines. You might want to have a look at this one. https://github.com/krzysztofzablocki/smooth-drawing