0

私の問題は次のとおりです-以下の関数を使用できます: takeSnapshotOfScreen を使用して、UIView に画像しか存在しない場合に、適切にスケーリングされた画面のスナップショットを取得します。ただし、ラベルを追加すると、以下に示すように、最終的なスナップショット イメージは、実際のテキストを含むラベルの代わりに、CustomLabelClass があるべき中央に重ね合わされた大きなイメージの小さくつぶされたバージョンで保存されます。

私の推測では、関数内から CG コンテキストを取得するための呼び出し: drawTextInRect (CustomLabelClass 内) は、呼び出し関数 takeSnapshotOfScreen によって取得されたコンテキストを再利用しているようです。

私の推測が正しければ、そのようなシナリオを適切に処理するにはどうすればよいでしょうか?

あらゆる支援に心から感謝します。ほんとうにありがとう!

  • コードと詳細-

以下は、この重ね合わせ/コンテキストの問題を示すサンプル画像です。

ここに画像の説明を入力

drawTextInRect をオーバーライドしてテキストの周りに境界線を描画するカスタム UILabel クラスがあります。

@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 に答える