将子视图插入到我添加了子视图和子图层的视图中

问题描述 投票:0回答:1

我将以下

CAShapeLayers
UIViews
设置附加到
UIView

[self.layer addSublayer:self.shapeLayer1];

if (someCase)
{
    [self.layer addSublayer:self.shapeLayerOptional];
}

[self.layer addSublayer:self.shapeLayer2];
[self addSubview: self.view1];

我希望有一个功能允许用户在 shapeLayer2 之前插入另一个

UIView
,我们称之为
view0
,但我不知道如何实现这一点。父级
UIView
subviews
属性仅包含
view1
,而其
layer.sublayers
属性包含 shapelayers 和 subview1 的图层,但我不想将
subview0.layer
插入到
layers.sublayers
中,因为
subview0
有一个
UITouchGestureRecognizer
。表面上这似乎是一个简单的设计问题,但由于某种原因它确实让我感到困惑。有人有任何推荐的解决方案吗?如果可以的话,我想尝试避免将
CAShapeLayers
包装成
UIViews

ios objective-c uiview calayer cashapelayer
1个回答
0
投票

有几点需要注意...

图层 - 无论是

CALayer
CAShapeLayer
CAGradientLayer
等 - 都属于视图。您可以通过
.zPosition
操纵图层的外观。

此外,图层本身并不真正存在...它必须作为子图层添加到视图的图层中。

视图有自己的图层...因此,在尝试操纵图层顺序时,必须考虑到这一点。


因此,您的目标是拥有一个具有多个图层的视图,另一个具有一个或多个图层的视图,以及在第一个视图的图层之间插入第二个视图(及其图层)。

如果我们从两个视图开始——黄色,有两个

CAShapeLayer
子层;带有一个
CAShapeLayer
子层的青色:

看起来像这样(分层):

我们想要在yellowView的矩形和椭圆形层之间插入cyanView(及其三角形子层):

让我们添加cyanView作为yellowView的子视图,偏移40,40和

yellowView.clipsToBounds = true
,这样我们就可以看到它是一个子视图:

这给了我们我们所期望的......但不是我们想要的,因为矩形和椭圆形层属于yellowView。

要将椭圆形层移动到顶部,我们将更改

.zPosition
属性:

// we don't want to mess with the .zPosition of yellow view's layer,
//  because it's the "base" of the hierarchy
rectShapeLayer.zPosition = 1;
cyanView.layer.zPosition = 2;
triShapeLayer.zPosition = 3;
ovalShapeLayer.zPosition = 4;

我们得到这个结果:

cyanView 及其三角形层现在位于黄色视图的矩形和椭圆形层之间。

目标达成了吗?也许...

现在让我们看看调试视图层次结构:

请注意,图层并未与其视图分离。

在上面的第一个层次结构图像中,我使用单独的视图只是为了展示我们正在尝试做的事情。


现在,管理

.zPosition
可能对你有用...但我认为仅实现图层或仅实现视图会更容易(我们可以更改视图的图层类以消除添加的需要)每个视图的子层)。


这里是一些生成上述内容的示例代码:

ViewsAndLayersViewController.h

#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ViewsAndLayersViewController : UIViewController
@end
NS_ASSUME_NONNULL_END

ViewsAndLayersViewController.m

#import "ViewsAndLayersViewController.h"

@implementation ViewsAndLayersViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.systemBackgroundColor;
    
    info = [UILabel new];
    info.numberOfLines = 0;
    info.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:info];
    
    UILayoutGuide *g = self.view.safeAreaLayoutGuide;
    
    [NSLayoutConstraint activateConstraints:@[
        [info.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
        [info.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
        [info.topAnchor constraintEqualToAnchor:g.topAnchor constant:20.0],
    ]];
    
    [self reset];
    
}

- (void)reset {
    [cyanView removeFromSuperview];
    [yellowView removeFromSuperview];
    cyanView = nil;
    yellowView = nil;
    
    yellowView = [UIView new];
    cyanView = [UIView new];
    rectShapeLayer = [CAShapeLayer new];
    ovalShapeLayer = [CAShapeLayer new];
    triShapeLayer = [CAShapeLayer new];
    
    yellowView.clipsToBounds = YES;
    
    [self.view addSubview:yellowView];
    [self.view addSubview:cyanView];
    
    CGRect r = CGRectMake(40.0, 160.0, 240.0, 200.0);
    yellowView.frame = r;
    cyanView.frame = CGRectOffset(r, 0.0, r.size.height + 20.0);
    
    yellowView.backgroundColor = UIColor.yellowColor;
    cyanView.backgroundColor = UIColor.cyanColor;
    
    for (CAShapeLayer *s in @[rectShapeLayer, ovalShapeLayer, triShapeLayer]) {
        s.fillColor = UIColor.clearColor.CGColor;
        s.lineWidth = 16;
        s.lineJoin = kCALineJoinRound;
    }
    
    rectShapeLayer.strokeColor = UIColor.systemRedColor.CGColor;
    ovalShapeLayer.strokeColor = UIColor.systemGreenColor.CGColor;
    triShapeLayer.strokeColor = UIColor.systemBlueColor.CGColor;
    
    [yellowView.layer addSublayer:rectShapeLayer];
    [yellowView.layer addSublayer:ovalShapeLayer];
    [cyanView.layer addSublayer:triShapeLayer];
    
    UIBezierPath *pth;
    CGRect pRect = CGRectInset(yellowView.bounds, 20.0, 20.0);
    CGPoint p;
    
    // rectangle path
    pth = [UIBezierPath bezierPathWithRect:pRect];
    rectShapeLayer.path = pth.CGPath;
    
    // oval path
    pth = [UIBezierPath bezierPathWithOvalInRect:pRect];
    ovalShapeLayer.path = pth.CGPath;
    
    // triangle path
    pth = [UIBezierPath new];
    p = CGPointMake(CGRectGetMidX(pRect), CGRectGetMinY(pRect));
    [pth moveToPoint:p];
    p = CGPointMake(CGRectGetMaxX(pRect), CGRectGetMaxY(pRect));
    [pth addLineToPoint:p];
    p = CGPointMake(CGRectGetMinX(pRect), CGRectGetMaxY(pRect));
    [pth addLineToPoint:p];
    [pth closePath];
    triShapeLayer.path = pth.CGPath;
    
    info.text = @"Tap to add cyanView as a subview of yellowView, offset by 40,40";
    iStep = 0;
    
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    ++iStep;
    
    switch (iStep) {
        case 1:
            [self step1];
            break;
            
        case 2:
            [self step2];
            break;
            
        case 3:
            [self step3];
            break;
            
        default:
            break;
    }
}

- (void)step1 {
    cyanView.frame = CGRectOffset(yellowView.bounds, 40.0, 40.0);
    [yellowView addSubview:cyanView];
    info.text = @"Tap to arrange layers via .zPosition";
}
- (void)step2 {
    // we don't want to mess with the .zPosition of yellow view's layer,
    //  because it's the "base" of the hierarchy
    rectShapeLayer.zPosition = 1;
    cyanView.layer.zPosition = 2;
    triShapeLayer.zPosition = 3;
    ovalShapeLayer.zPosition = 4;
    info.text = @"Tap to reset...";
}
- (void)step3 {
    [self reset];
}

@end
© www.soinside.com 2019 - 2024. All rights reserved.