0

我的问题如下 - 我可以使用以下功能:当任何 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
4

1 回答 1

0

解决方案是setNeedsDisplay在包含手动呈现文本的子视图上设置,因为我正在覆盖drawTextInRect.

于 2012-12-08T03:22:07.730 回答