I'm trying to put a string in a rectangular form via drawInRect:withAttributes: method. The official documentation writes: "Draws the receiver with the font and other display characteristics of the given attributes, within the specified rectangle in the currently focused UIView."
This action should be done on a button event. But it doesn't work at all. Nothing is shown.
The code that I use:
- (IBAction)buttonPressed:(id)sender
{
// some area on the top (a part of UIView)
CGRect rect = CGRectMake(50, 50, 100, 100);
// my text
NSString *str = #"Eh, what's wrong with this code?";
// crappy attributes
NSDictionary *attributes = #{NSFontAttributeName: [UIFont boldSystemFontOfSize:8]};
// and finally passing a message
[str drawInRect:rect withAttributes:attributes];
}
Is there a particular kind of areas that might be used for drawing strings in rects? Or is it possible to draw a string in a rect where I'd like it to be? Please, help me understand it better!
But it doesn't work at all. Nothing is shown.
That's because no drawing context is set up when you run that code. You're looking at drawing as something that you can do whenever you feel like it, but in fact drawing is something that you should only do when the system asks you to. At other times, you should instead remember what you want to draw, and then draw it when the time comes.
When is "the time" to draw? It's when your view's -drawRect: method is called. Since your method is an action, it looks like you're probably trying to do the drawing in a view controller. What you want to do instead is to subclass UIView and override -drawRect: to draw what you want.
It doesn't work that way, you first need to make a CGContextRef where you will draw the text.
Your code is fine, just place everything within drawRect.
Related
I used CoreText to layout a custom view. Want to know on which word I tapped on event/gesture with CoreText.
I did following code within my drawRect:
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSelectFont(context, "Helvetica-Bold", FONTSIZE, kCGEncodingMacRoman);
//setSpan
CGContextSetTextPosition(context, 0, (200+offset) - (i*25));
CGContextShowText(context,[[dispLineArray objectAtIndex:i] UTF8String], strlen([[dispLineArray objectAtIndex:i] UTF8String]));
in this answered question you can find information about CoreText and touch gestures:
Using CoreText and touches to create a clickable action (not tested by me!)
In the example you can see how to get the string character index from the touch position. After this, you can extract the word using differents methods like split the NSString in two NSString by character position, then split boths by white space character. Now, we have two NSArray. After this take last and first element of boths NSArray and merge into one NSString.
And you have the word.
It's a rudimentary and surely there are better ways to do this using regular expressions or other techniques.
If display view is a uiview .You can use view's gestureRecognizer do it .
If display view is a custom GTFrameRef use uiresponse touch founcations .
I've got a simple UIView class that draws some text in it's drawRect routine:
[mString drawInRect:theFrameRect withFont:theFont];
That looks OK at regular resolution, but when zoomed, it's fuzzy:
[image removed, not enough posts]
So, I added some tiling:
CATiledLayer *theLayer = (CATiledLayer *) self.layer;
theLayer.levelsOfDetailBias = 8;
theLayer.levelsOfDetail = 8;
theLayer.tileSize = CGSizeMake(1024,1024);
(plus the requisite layerClass routine)
but now the text will draw twice, when zoomed, when the size of the frame is larger than the size of tile:
[image removed, not enough posts]
I'm not clear as to the solution for this. Drawing the text is an atomic operation. I could figure out how to calculate what portion of the text to draw based on the rect that's passed in...but is that really the way to go? Older code examples use drawLayer, but that seems to have been obviated by iOS 5, and is clearly more cumbersome than a straight drawRect call.
I am currently creating PDF documents from a UIView in iOS by using CALayer and the renderInContext method.
The problem I am facing is the sharpness of labels. I have created a UILabel subclass that overrides drawLayer like so:
/** Overriding this CALayer delegate method is the magic that allows us to draw a vector version of the label into the layer instead of the default unscalable ugly bitmap */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());
if (!layer.shouldRasterize && isPDF)
[self drawRect:self.bounds]; // draw unrasterized
else
[super drawLayer:layer inContext:ctx];
}
This method lets me draw nice crisp text, however, the problem is with other views that I don't have control over. Is there any method that would allow me to do something similar for labels embedded in UITableView or UIButton. I guess I'm looking for a way to iterate through the view stack and do something to let me draw sharper text.
Here is an example:
This text renders nicely (my custom UILabel subclass)
The text in a standard segmented control isn't as sharp:
Edit: I am getting the context to draw into my PDF as follows:
UIGraphicsBeginPDFContextToData(self.pdfData, CGRectZero, nil);
pdfContext = UIGraphicsGetCurrentContext();
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
[view.layer renderInContext:pdfContext];
I ended up traversing the view hierarchy and setting every UILabel to my custom subclass that overrides drawLayer.
Here is how I traverse the views:
+(void) dumpView:(UIView*) aView indent:(NSString*) indent {
if (aView) {
NSLog(#"%#%#", indent, aView); // dump this view
if ([aView isKindOfClass:[UILabel class]])
[AFGPDFDocument setClassForLabel:aView];
if (aView.subviews.count > 0) {
NSString* subIndent = [[NSString alloc] initWithFormat:#"%#%#",
indent, ([indent length]/2)%2==0 ? #"| " : #": "];
for (UIView* aSubview in aView.subviews)
[AFGPDFDocument dumpView:aSubview indent:subIndent];
}
}
}
And how I change the class:
+(void) setClassForLabel: (UIView*) label {
static Class myFancyObjectClass;
myFancyObjectClass = objc_getClass("UIPDFLabel");
object_setClass(label, myFancyObjectClass);
}
The comparison:
Old:
New:
Not sure if there is a better way to do this, but it seems to work for my purposes.
EDIT: Found a more generic way to do this that doesn't involve changing the class or traversing through the whole view hierarchy. I am using method swizzling. This method also lets you do cool things like surrounding every view with a border if you want. First I created a category UIView+PDF with my custom implementation of the drawLayer method, then in the load method I use the following:
// The "+ load" method is called once, very early in the application life-cycle.
// It's called even before the "main" function is called. Beware: there's no
// autorelease pool at this point, so avoid Objective-C calls.
Method original, swizzle;
// Get the "- (void) drawLayer:inContext:" method.
original = class_getInstanceMethod(self, #selector(drawLayer:inContext:));
// Get the "- (void)swizzled_drawLayer:inContext:" method.
swizzle = class_getInstanceMethod(self, #selector(swizzled_drawLayer:inContext:));
// Swap their implementations.
method_exchangeImplementations(original, swizzle);
Worked from the example here: http://darkdust.net/writings/objective-c/method-swizzling
i want to split the view into three different parts.each part i want to set different color.
i have tried using drawing methods in drawrect.i've succeded but the splitting should be done on button click.
here is the code that i have used.
-(void)drawRect:(CGRect)rect
{
int i=0;
float width =rect.size.width/[elements count];
CGRect paintRect;
for (NSString *color in self.elements)
{
paintRect = CGRectMake(rect.origin.x+(i*width), rect.origin.y, width, rect.size.height);
i++;
UIColor *colorr=[UIColor colorWithHexString:color];
[colorr set];
UIRectFill(paintRect);
}
}
enter code here
now i want to use this code on button click.....
help...thanx in advanced
a much easier way to do this would be to put three custom buttons or custom views and arrange them in code.
Put the backcolor of the button or view to the selections you want.
And in the case of button you attach the UIControlEventTouchUpInside event and trap the touch.
in the case of a view. you would subclass the view and override the touch events associated to that view and build your own "click" event
This is a lot less complicated than trying to create your own touch locations in a single view.
Another option would be to grab the color at the pixel that is touched. there are a lot of examples of this on stackoverflow. here is one
Hope that helps
I'm trying to draw a UIlabel into a new Context, at a specific location. I know you can draw just the NSString into a context easily, but I want to retain the text size, color, and word wrap style of the UILabel. Thanks for your help!
UIGraphicsBeginImageContext(targetSize);
// here is where I want to draw UILabel to context
UIGraphicsEndImageContext();
You could draw any view using -renderInContext:, but if all you need is just retain the text size, color and word wrap style, you could simply use -drawInRect:withFont:lineBreakMode:alignment: to customize all options.
[label.textColor set];
[label.text drawInRect:label.bounds
withFont:label.font
lineBreakMode:label.lineBreakMode
alignment:label.textAlignment];
There is also a -drawTextInRect: method in UILabel, but Apple says "You should not call this method directly."