我的问题如下 - 我可以使用以下功能:当任何 UIView 中仅存在图像时,takeSnapshotOfScreen 可以对屏幕进行适当缩放的快照。但是,当我添加标签时,如下所示,最终的快照图像会保存为较大图像的较小、压扁的版本,叠加在 CustomLabelClass 应该位于的中心,而不是包含实际文本的标签。
我的猜测是,从函数中获取 CG 上下文的调用:drawTextInRect(在 CustomLabelClass 中),似乎正在重用调用函数 takeSnapshotOfScreen 检索到的上下文,因为我猜它从未弹出。
如果我的猜测是正确的,如何正确处理这种情况?
我真诚地感谢任何帮助。对此,我真的非常感激!
- 代码和详细信息-
下面是一个示例图像,演示了这个叠加/上下文问题。
我有一个自定义 UILabel 类,我在其中覆盖 drawTextInRect 以在文本周围绘制边框:
@interface CustomLabelClass : UILabel {
@property (nonatomic, strong) UIColor *innerColor;
@property (nonatomic, strong) UIColor *borderColor;
}
@implementation CustomLabelClass
@synthesize innerColor, borderColor;
...
- (void)drawTextInRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetTextDrawingMode(context, kCGTextFill);
if(innerColor)
[self setTextColor:innerColor];
// Draw the text without an outline
[super drawTextInRect:rect];
CGImageRef alphaMask = NULL;
// Create a mask from the text
alphaMask = CGBitmapContextCreateImage(context);
// Outline width
CGContextSetLineWidth(context, 4);
CGContextSetLineJoin(context, kCGLineJoinRound);
// Set the drawing method to stroke
CGContextSetTextDrawingMode(context, kCGTextStroke);
// Outline color
if(borderColor)
self.textColor = borderColor;
// notice the +1 for the y-coordinate. this is to account for the face that the outline appears to be thicker on top
[super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y+1, rect.size.width, rect.size.height)];
// Draw the saved image over the outline. Invert because CoreGraphics works with an inverted coordinate system
CGContextTranslateCTM(context, 0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, rect, alphaMask);
// Clean up because ARC doesnt handle CoreGraphics
CGImageRelease(alphaMask);
UIGraphicsEndImageContext();
}
我有另一个使用 CustomLabelClass 的类,如下所示:
#import "CustomLabelClass.h"
@implementation CustomViewController
-(void)createCustomLabel{
//...create a CustomLabelClass *newLabel object...etc.
...
// add it to the view
[[[self view] viewWithTag:ViewContainingImageAndCustomLabels] addSubview:newLabel];
}
-(void)updateCurrentImage{
// Assume that the object: mainImage, is a global UIImage, for purposes of these code snippets.
UIImageView *mainImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, mainImage.size.width, mainImage.size.height)];
mainImageView.image = mainImage;
[mainImageView setTag:ViewTypeMainPhoto];
// we always want the image to be the underlying view, so insert it at Index:0
[[[self view] viewWithTag:ViewContainingImageAndCustomLabels] insertSubview:mainImageView atIndex:0];
}
-(UIImage *)takeSnapshotOfScreen{
// Mostly taken from: http://developer.apple.com/library/ios/#qa/qa1703/_index.html
//
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize imageSize = [[UIScreen mainScreen] bounds].size;
if (NULL != UIGraphicsBeginImageContextWithOptions){
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0.0f); // 0.0f scale is for retina bc *WithOptions captures native resolution
}else{
UIGraphicsBeginImageContext(imageSize);
}
CGContextRef context = UIGraphicsGetCurrentContext();
// Iterate over every window from back to front
for (UIView *tempView in [[[self view] viewWithTag:ViewContainingImageAndCustomLabels] subviews])
{
// -renderInContext: renders in the coordinate space of the layer,
// so we must first apply the layer's geometry to the graphics context
CGContextSaveGState(context);
// Center the context around the window's anchor point
CGContextTranslateCTM(context, [tempView center].x, [tempView center].y);
// Apply the window's transform about the anchor point
CGContextConcatCTM(context, [tempView transform]);
// Offset by the portion of the bounds left of and above the anchor point
CGContextTranslateCTM(context,
-[tempView bounds].size.width * [[tempView layer] anchorPoint].x,
-[tempView bounds].size.height * [[tempView layer] anchorPoint].y);
// Render the layer hierarchy to the current context
[[tempView layer] renderInContext:context];
// Restore the context
CGContextRestoreGState(context);
}
// Retrieve the screenshot image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); // remove context from stack
return image;
}
最后是一个只调用上述函数的函数(简化如下):
-(void)doEverything{
[self createCustomLabel];
[self updateCurrentImage];
[self takeSnapshotOfScreen];
}
@end