子视图的子层与更高的子视图重叠

Posted

技术标签:

【中文标题】子视图的子层与更高的子视图重叠【英文标题】:Subview's sublayers overlapping higher subviews 【发布时间】:2015-04-29 17:33:45 【问题描述】:

我有一个问题:我正在创建一个从方法返回的UIView,这部分很好,但我注意到,当我将子层添加到其中一个子视图时,这些层重叠层次结构中较高的子视图(textView 和 imageView)添加到 testViewCopy 的子层出现在这些子视图的顶部,它们不应该出现。我不知道这里发生了什么。

代码:

- (void)makeShareImages

    UIView *shareView = [self shareView];

    UIView *testViewCopy = [shareView viewWithTag:0];

    NSUInteger currentIndex = 1;

    for (NSDictionary *sub in self.array)
    
        NSArray *lastArray = [sub objectForKey:@"LastArray"];

        for (NSDictionary *dict in lastArray)
        
            @autoreleasepool
            
                currentIndex ++;

                CircleLayer *layer = [[CircleLayer alloc]init];
                layer.portrait = [[dict objectForKey:@"Portrait"]boolValue];

                layer.frame = testViewCopy.bounds;

                [testViewCopy.layer addSublayer:layer];

                NSData *frameData = [self getSnapshotDataFromView:shareView];

                NSString *savePath = [NSString stringWithFormat:@"%@/%lu.png",somePath,(unsigned long)currentIndex];

                [frameData writeToFile:savePath options:0 error:nil];
            
        
    


- (UIView *)shareView

    UIColor *bgColor = self.containerView.backgroundColor;

    CGSize size = self.containerView.bounds.size;

    UIView *viewToShare = [[UIView alloc]init];
    viewToShare.backgroundColor = bgColor;
    viewToShare.layer.cornerRadius = 6.0;
    viewToShare.layer.masksToBounds = YES;

    UIView *testViewCopy = [[UIView alloc]init];
    testViewCopy.backgroundColor = [UIColor clearColor];
    testViewCopy.contentMode = UIViewContentModeScaleAspectFit;
    testViewCopy.layer.masksToBounds = YES;
    testViewCopy.tag = 0;

    UITextView *textViewCopy = [[UITextView alloc]init];
    textViewCopy.backgroundColor = [UIColor clearColor];
    textViewCopy.tag = 1;
    textViewCopy.textContainerInset = self.textView.textContainerInset;

    UIImageView *profileImageViewCopy = [[UIImageView alloc]initWithFrame:CGRectMake(2, 2, 32, 32)];
    profileImageViewCopy.contentMode = UIViewContentModeScaleAspectFit;
    profileImageViewCopy.layer.masksToBounds = YES;
    profileImageViewCopy.image = [self profileImage];
    profileImageViewCopy.tag = 2;
    profileImageViewCopy.layer.cornerRadius = profileImageViewCopy.frame.size.width / 2.0;

    viewToShare.frame = CGRectMake(0, 0, size.width, size.height);
    testViewCopy.frame = CGRectMake(0, 0, size.width, size.width);
    textViewCopy.frame = CGRectMake(0, 0, size.width, size.height);

    NSAttributedString *attributedStringCopy = [[NSAttributedString alloc]initWithAttributedString:self.textView.attributedText];

    textViewCopy.attributedText = attributedStringCopy;

    [viewToShare addSubview:testViewCopy];
    [viewToShare addSubview:textViewCopy];
    [viewToShare addSubview:profileImageViewCopy];

    return viewToShare;


- (NSData *)getSnapshotDataFromView:(UIView *)view

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *snapShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return UIImagePNGRepresentation(snapShot);

【问题讨论】:

【参考方案1】:

您的代码运行正常。所有同级视图 - 一个公共父视图的子视图 - 都有一个明确的分层顺序,从后到前。 addSubview: 将子视图添加为其兄弟中的 last ;因此,它在同一个父视图的所有现有子视图之前分层。如果这不是您想要的,请将子视图从前面插入到另一层,或者添加它(在前面),然后按分层顺序将它移到后面。

此外(在这里我认为我们越来越接近您注意到的特定现象),视图本身只是层。因此,视图的分层顺序实际上是层的分层顺序的一个子集。我刚才所说的关于视图的事情同样适用于层,因为视图层:如果您将子层添加到超级层,它会添加到该超级层的所有其他子层之前,如果该超级层实际上是一个视图,则包括任何子视图。

正如我在当前版本的书中所写:

视图的子视图的底层是该视图的底层的子层,就像该视图的底层的任何其他子层一样。因此,它可以按绘图顺序放置在它们之间的任何位置。一个视图可以散布在其父视图底层的子层之间,这让初学者感到惊讶。

听起来您刚刚发现了这一点,并且感到相当惊讶。

从绘制渲染树的角度来考虑它可能会有所帮助。换句话说,与其考虑事物的外观,不如考虑ios 做了什么。一个层可以有一个超层,除了最终的超层,一个层可以有一个先前的兄弟,除了超层的第一个子层。相反,一个层可以有子层,它可以有下一个兄弟。我们首先绘制最终的超层(窗口)。然后,对于我们刚刚绘制的每一层,依次遵循以下两条规则:

绘制它的第一个子层,如果有的话。

绘制它的下一个兄弟,如果有的话。

每次我们绘制一个图层时,它都在我们之前绘制的所有东西的前面。因此,一个超层的所有子层都出现在超层的前面,而所有后面的兄弟(及其子层)都出现在所有先前的兄弟(及其子层)的前面。这会产生您在屏幕上看到的内容。

(但是,请注意,您拥有更大的灵活性,因为在同级之间,您可以通过设置图层的zPosition 属性来操纵绘制顺序而无需重新排列同级。)

【讨论】:

请查看我更新的问题,我发现子视图的顺序正确。问题是图层添加到层次结构中较低的子视图之一与较高的视图重叠。 我不知道您所说的“等级较低”是什么意思。而且您没有提供有关现有视图层次结构的信息;你的问题非常模糊。但是,我已经向您描述了它的工作方式。如果您看到的不是您所期望的,我只能建议您不了解分层顺序,或者您实际上不知道层次结构中视图和图层的分层顺序。 我刚刚告诉过你。将子图层添加到层次结构子视图中的较低位置不应与层次结构子视图中的较高位置重叠。我不是指子视图,而是子层。 好的,我会把它添加到我的答案中。等一下。 很抱歉给您带来了困惑!

以上是关于子视图的子层与更高的子视图重叠的主要内容,如果未能解决你的问题,请参考以下文章

如何根据与其添加对应的索引删除子层?

如何在 Swift 中调整视图中的子层大小?

每次视图出现时,UIView 层的子层显示不同/随机

SwiftUI 布局(Layout)基础

添加 AVPlayerLayer 作为当前视图的子层在 iPhone 5 上不起作用

将大于 cellHeight 的子视图添加到 UITableViewCell?