更改图层Z位置时,renderInContext无法正常工作

时间:2015-11-27 07:15:07

标签: ios objective-c iphone uiimageview calayer

我的应用程序允许用户前后切换UIImageView,然后用户可以捕获该屏幕。以下是将屏幕捕获到UIImage

的代码
-(UIImage *)imageWithView:(UIView *)view
{
   UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 2.0f);

// I even tried view.layer.presentationLayer but still not working
[view.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();


return image;

}

我不使用[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES],因为它较慢,有时(当视图不可见时)以黑色绘制屏幕截图。

但是renderInContext的问题是在UIImageView ( imageView.layer.zPosition = 0.01;etc )之间改变的Z位置。在我的iPhone屏幕中,当我为zPosition指定值时,这正常工作,但在捕获屏幕中,它显示错误。

无论如何我可以解决这个问题吗?提前致谢

编辑: 这是我在捕获屏幕截图之前尝试做的事情。我使用此代码将一个ImageView显示在另一个之前。

-(void)bringOneLevelUp:(UIImageView*)imageView
{
//_imgArray is sorted by Z position order (small to big)
    NSUInteger currentObjectIndex = [_imgArray indexOfObject:imageView];


if(currentObjectIndex+1< _imgArray.count){

UIImageView *upperImageView = [_imgArray objectAtIndex:currentObjectIndex+1];


    CGFloat currentZIndex = imageView.layer.zPosition;
    CGFloat upperZIndex= upperImageView.layer.zPosition;

    imageView.layer.zPosition = upperZIndex;
    upperImageView.layer.zPosition = currentZIndex;


// swap position in array 
[_imgArray exchangeObjectAtIndex:currentObjectIndex withObjectAtIndex:currentObjectIndex+1];

}

}

并且喜欢我之前解释过手机屏幕中此代码的结果是正确的。 newImageView位于lastImageView的前面。但是当我通过renderInContext捕获截图时。他们不是。

4 个答案:

答案 0 :(得分:0)

我也有这个问题。我希望在使用renderInContext()之后在图像上绘制文本。我通过在将它们添加到窗口时定位我的视图而不是使用图层来设置z位置来解决这个问题。

我曾经有一个文本字段可以将z位置设置为:

layer?.zPosition = 1

我删除了此代码,而在将图像添加到窗口时,我使用了:

addSubview(image, positioned: .Below, relativeTo: nil)

这解决了这个问题。

答案 1 :(得分:0)

我面临着同样的问题,这真是令人沮丧。

我知道这个问题是在大约2年前提出的,所以无论如何,如果有帮助,这就是答案

因此,更改子视图zPosition在应用程序中的渲染效果很好,但实际上在创建截图时会影响renderByContext。我不知道为什么,我认为这是一个错误。

因此,为了使屏幕截图在应用程序中呈现时正确显示,我们需要按照zPosition指定的正确顺序在所有子视图上手动调用renderByContext

    UIGraphicsBeginImageContext(self.view.frame.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [self renderInContext:ctx];

    UIImage *screenShotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

-(void) renderInContext:(CGContextRef)ctx {
    CGContextBeginTransparencyLayer(ctx, NULL);
    //self.layers is a desc ordered list of views based on its zPosition
    for(UIView *view in self.layers){ 
        [view.layer renderInContext:ctx];
    }
    CGContextEndTransparencyLayer(ctx);
}

答案 2 :(得分:0)

Swift 4.2

@RameshVel的答案对我有用,将其翻译为 Swift ,也许有人需要这个:

 UIGraphicsBeginImageContext(drawingCanvas.frame.size)
 self.renderInContext(ct: UIGraphicsGetCurrentContext()!)

 guard let image = UIGraphicsGetImageFromCurrentImageContext() else {return}
 UIGraphicsEndImageContext()

在renderInContext函数中:

 func renderInContext(ct:CGContext){

    ct.beginTransparencyLayer(auxiliaryInfo: nil)

    // descendant ordered list of views based on its z-position
    let orderedLayers = self.view.subviews.sorted(by: {
        $0.layer.zPosition < $1.layer.zPosition
    })

    for l in orderedLayers {
        l.layer.render(in: ct)
    }
    ct.endTransparencyLayer()
}

如果您要绘制和添加层,则可以使用 CALayers 来做到这一点:

 UIGraphicsBeginImageContext(drawingCanvas.frame.size)
 //Canvas is a custom UIView for drawing
 self.renderInContext(ct: UIGraphicsGetCurrentContext()!, canvas: canvas)

 guard let image = UIGraphicsGetImageFromCurrentImageContext() else {return}
 UIGraphicsEndImageContext()

renderInContext函数:

func renderInContext(ct:CGContext, canvas:CustomCanvas){

    ct.beginTransparencyLayer(auxiliaryInfo: nil)
    let layers:[CALayer] = canvas.layer.sublayers!

    let orderedLayers = layers.sorted(by: {
        $0.zPosition < $1.zPosition
    })

    for v in orderedLayers {
        v.render(in: ct)
    }
    ct.endTransparencyLayer()
}

答案 3 :(得分:0)

这是Apple的一个烦人的bug,但是解决方案很简单,只需使用比较器根据zPositions递归地重新排列快照子视图(及其子视图(等等))的视图。

只需在调用快照之前直接调用以下方法,将要快照的视图传递给它即可。

///UIGraphicsGetCurrentContext doesn't obey layer zPositions so have to adjust view heirarchy (integer index) to match zpositions (float values) for all nested subviews.
-(void)recursivelyAdjustHeirarchyOfSubviewsBasedOnZPosition:(UIView *)parentView {

    NSArray *sortedSubviews = [[parentView subviews] sortedArrayUsingComparator:
                           ^NSComparisonResult(UIView *view1, UIView *view2)
                           {
                               float zpos1 = view1.layer.zPosition;
                               float zpos2 = view2.layer.zPosition;
                               return zpos1 > zpos2;
                           }];

    for (UIView *childView in sortedSubviews) {
        [parentView bringSubviewToFront:childView];
        [self recursivelyAdjustHeirarchyOfSubviewsBasedOnZPosition:childView];
    }

}