使用自动布局时,如何调整 CALayer 的锚点?

Posted

技术标签:

【中文标题】使用自动布局时,如何调整 CALayer 的锚点?【英文标题】:How do I adjust the anchor point of a CALayer, when Auto Layout is being used? 【发布时间】:2012-10-08 05:30:54 【问题描述】:

注意:自从提出这个问题以来,事情已经发生了变化;请参阅 here 了解最近的概述。


在自动布局之前,您可以通过存储框架、设置锚点和恢复框架来更改视图层的锚点而不移动视图。

在自动布局的世界中,我们不再设置框架,但约束似乎无法完成将视图位置调整回我们想要的位置的任务。您可以破解约束来重新定位您的视图,但在旋转或其他调整大小事件时,这些再次变得无效。

以下好主意不起作用,因为它会创建“布局属性(左和宽度)的无效配对”:

layerView.layer.anchorPoint = CGPointMake(1.0, 0.5);
// Some other size-related constraints here which all work fine...
[self.view addConstraint:
    [NSLayoutConstraint constraintWithItem:layerView
                                 attribute:NSLayoutAttributeLeft
                                 relatedBy:NSLayoutRelationEqual 
                                    toItem:layerView 
                                 attribute:NSLayoutAttributeWidth 
                                multiplier:0.5 
                                  constant:20.0]];

我的意图是设置 layerView 的左边缘,调整锚点的视图,宽度的一半加上 20(我希望从超级视图的左边缘插入的距离)。

是否可以在使用自动布局布局的视图中更改锚点而不更改视图的位置?我是否需要使用硬编码值并在每次旋转时编辑约束?我希望不会。

我需要更改锚点,以便在对视图应用变换时获得正确的视觉效果。

【问题讨论】:

鉴于您在这里所拥有的一切,即使您让上面的代码正常工作,您似乎最终还是会得到模棱两可的布局。 layerView 怎么知道它的宽度?它的右侧是否粘在其他东西上? 这在//Size-related constraints that work fine 中有介绍——层视图的宽度和高度是从父视图的。 【参考方案1】:

[编辑:警告:随后的整个讨论可能会过时,或者至少会被 ios 8 大大减轻,这可能不再犯在视图转换时触发布局的错误应用。]

自动布局与视图变换

自动布局在视图变换方面表现不佳。据我所知,原因是您不应该弄乱具有变换(默认标识变换除外)的视图的框架 - 但这正是自动布局所做的。自动布局的工作方式是在layoutSubviews 中运行时冲破所有约束并相应地设置所有视图的框架。

换句话说,约束不是魔法;它们只是一个待办事项清单。 layoutSubviews 是完成待办事项列表的地方。它通过设置框架来实现。

我不禁认为这是一个错误。如果我将此转换应用于视图:

v.transform = CGAffineTransformMakeScale(0.5,0.5);

我希望看到视图的中心位于与之前相同的位置,并且大小只有一半。但根据它的限制,这可能不是我所看到的。

[实际上,这里还有第二个惊喜:对视图应用变换会立即触发布局。在我看来,这似乎是另一个错误。或者也许它是第一个错误的核心。我期望的是至少在布局时间之前能够摆脱变换,例如设备旋转 - 就像我可以在布局时间之前使用帧动画一样。但实际上布局时间是即时的,这似乎是错误的。]

解决方案 1:无约束

当前的一个解决方案是,如果我要对视图应用半永久性变换(而不仅仅是以某种方式临时摇摆它),则删除影响它的所有约束。不幸的是,这通常会导致视图从屏幕上消失,因为自动布局仍然发生,现在没有约束告诉我们将视图放在哪里。所以除了移除约束之外,我将视图的translatesAutoresizingMaskIntoConstraints 设置为YES。该视图现在以旧方式工作,实际上不受自动布局的影响。 (很明显,它受到自动布局的影响,但是隐式的自动调整掩码约束会导致其行为就像在自动布局之前一样。)

解决方案 2:仅使用适当的约束

如果这看起来有点激烈,另一种解决方案是设置约束以与预期的转换一起正常工作。例如,如果一个视图的大小完全由它的内部固定宽度和高度决定,并且完全由它的中心定位,那么我的比例变换将按我的预期工作。在这段代码中,我删除了子视图 (otherView) 上的现有约束,并用这四个约束替换它们,给它一个固定的宽度和高度,并完全按其中心固定它。之后,我的比例变换工作:

NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
    if (con.firstItem == self.otherView || con.secondItem == self.otherView)
        [cons addObject:con];

[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];

结果是,如果您没有影响视图框架的约束,自动布局将不会触及视图的框架 - 这正是您在涉及转换时所追求的。

解决方案 3:使用子视图

上述两种解决方案的问题是我们失去了约束来定位我们的视图的好处。所以这里有一个解决方案。从一个不可见的视图开始,它的工作只是充当主机,并使用约束来定位它。在其中,将真实视图作为子视图。使用约束将子视图定位在主视图中,但将这些约束限制为在我们应用变换时不会反击的约束。

这是一个插图:

白色视图是主机视图;你应该假装它是透明的,因此是不可见的。红色视图是它的子视图,通过将其中心固定到主视图的中心来定位。现在我们可以围绕它的中心缩放和旋转红色视图,没有任何问题,而且插图确实表明我们已经这样做了:

self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);

同时,当我们旋转设备时,主机视图的约束使其保持在正确的位置。

解决方案 4:改用层变换

使用层变换代替视图变换,它不会触发布局,因此不会立即与约束发生冲突。

例如,这个简单的“跳动”视图动画在自动布局下很可能会中断:

[UIView animateWithDuration:0.3 delay:0
                    options:UIViewAnimationOptionAutoreverse
                 animations:^
    v.transform = CGAffineTransformMakeScale(1.1, 1.1);
 completion:^(BOOL finished) 
    v.transform = CGAffineTransformIdentity;
];

尽管最终视图的大小没有变化,但仅仅设置它的transform 会导致布局发生,并且约束可以使视图跳来跳去。 (这感觉像是一个 bug 还是什么?)但是如果我们对 Core Animation 做同样的事情(使用 CABasicAnimation 并将动画应用到视图层),布局就不会发生,它工作正常:

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];

【讨论】:

转换不是导致我出现问题的原因,只是设置了新的锚点。不过,我将尝试消除约束并尝试自动调整大小的蒙版。 这里有什么不懂的。解决方案4:当一个transform应用于backing layer时,transform也会影响autolayout,因为view的transform属性是指backing layer的transform @Andy 相反,在 iOS 8 上问题完全消失了,我的整个答案是不必要的 @Sunkas 我在你的问题中回答了。 在 iOS 8 上,图层变换也会触发自动布局【参考方案2】:

我遇到了类似的问题,刚刚收到 Apple 自动布局团队的回复。他们建议使用 matt 建议的容器视图方法,但他们创建了一个 UIView 的子类来覆盖 layoutSubviews 并在那里应用自定义布局代码 - 它就像一个魅力

头文件看起来像这样,因此您可以直接从 Interface Builder 链接您选择的子视图

#import <UIKit/UIKit.h>

@interface BugFixContainerView : UIView
@property(nonatomic,strong) IBOutlet UIImageView *knobImageView;
@end

和 m 文件应用这样的特殊代码:

#import "BugFixContainerView.h"

@implementation BugFixContainerView
- (void)layoutSubviews

    static CGPoint fixCenter = 0;
    [super layoutSubviews];
    if (CGPointEqualToPoint(fixCenter, CGPointZero)) 
        fixCenter = [self.knobImageView center];
     else 
        self.knobImageView.center = fixCenter;
    

@end

如您所见,它在第一次调用时抓取视图的中心点,并在进一步调用中重用该位置,以便相应地放置视图。从这个意义上说,这会覆盖自动布局代码,它发生在 [super layoutSubviews] 之后;其中包含自动布局代码。

就像不再需要避免自动布局一样,但是当默认行为不再合适时,您可以创建自己的自动布局。当然,您可以应用比示例中更复杂的东西,但这就是我所需要的,因为我的应用程序只能使用肖像模式。

【讨论】:

感谢您发布此信息。自从我写下我的答案后,我绝对明白了覆盖layoutSubviews 的价值。不过,我只想补充一点,Apple 只是让 you 做我认为 他们 应该做的事情(在他们的 Autolayout 实现中)。 你是对的,但我想这与问题本身并没有真正的关系。由于他们提供了上述代码,我对此很满意! 自动布局团队自己建议创建一个自定义容器子类只是为了解决自动布局如何破坏视图系统中长期和直观的行为,这既可悲又荒谬。【参考方案3】:

我找到了一个简单的方法。它适用于 iOS 8 和 iOS 9。

就像在使用基于框架的布局时调整锚点:

let oldFrame = layerView.frame
layerView.layer.anchorPoint = newAnchorPoint
layerView.frame = oldFrame

当您使用自动布局调整视图的锚点时,您会做同样的事情,但是以约束的方式。当 anchorPoint 从 (0.5, 0.5) 变为 (1, 0.5) 时,layerView 会向左移动一个距离为视图宽度长度的一半,因此需要对此进行补偿。

我不明白问题中的约束。所以,假设您添加一个相对于 superView centerX 的 centerX 约束,并带有一个常量:layerView.centerX = superView.centerX + 常量

layerView.layer.anchorPoint = CGPoint(1, 0.5)
let centerXConstraint = .....
centerXConstraint.constant = centerXConstraint.constant + layerView.bounds.size.width/2

【讨论】:

给你一杯最好的啤酒,我的朋友。这是非常好的解决方法:D【参考方案4】:

如果您使用自动布局,那么从长远来看,我看不到手动设置位置将如何发挥作用,因为最终自动布局会破坏您在计算自己的布局时设置的位置值。

相反,我们需要修改布局约束本身,以补偿设置锚点所产生的变化。以下函数对未转换的视图执行此操作。

/**
  Set the anchorPoint of view without changing is perceived position.

 @param view view whose anchorPoint we will mutate
 @param anchorPoint new anchorPoint of the view in unit coords (e.g., 0.5,1.0)
 @param xConstraint an NSLayoutConstraint whose constant property adjust's view x.center
 @param yConstraint an NSLayoutConstraint whose constant property adjust's view y.center

  As multiple constraints can contribute to determining a view's center, the user of this
 function must specify which constraint they want modified in order to compensate for the
 modification in anchorPoint
 */
void SetViewAnchorPointMotionlesslyUpdatingConstraints(UIView * view,CGPoint anchorPoint,
                                                       NSLayoutConstraint * xConstraint,
                                                       NSLayoutConstraint * yConstraint)

  // assert: old and new anchorPoint are in view's unit coords
  CGPoint const oldAnchorPoint = view.layer.anchorPoint;
  CGPoint const newAnchorPoint = anchorPoint;

  // Calculate anchorPoints in view's absolute coords
  CGPoint const oldPoint = CGPointMake(view.bounds.size.width * oldAnchorPoint.x,
                                 view.bounds.size.height * oldAnchorPoint.y);
  CGPoint const newPoint = CGPointMake(view.bounds.size.width * newAnchorPoint.x,
                                 view.bounds.size.height * newAnchorPoint.y);

  // Calculate the delta between the anchorPoints
  CGPoint const delta = CGPointMake(newPoint.x-oldPoint.x, newPoint.y-oldPoint.y);

  // get the x & y constraints constants which were contributing to the current
  // view's position, and whose constant properties we will tweak to adjust its position
  CGFloat const oldXConstraintConstant = xConstraint.constant;
  CGFloat const oldYConstraintConstant = yConstraint.constant;

  // calculate new values for the x & y constraints, from the delta in anchorPoint
  // when autolayout recalculates the layout from the modified constraints,
  // it will set a new view.center that compensates for the affect of the anchorPoint
  CGFloat const newXConstraintConstant = oldXConstraintConstant + delta.x;
  CGFloat const newYConstraintConstant = oldYConstraintConstant + delta.y;

  view.layer.anchorPoint = newAnchorPoint;
  xConstraint.constant = newXConstraintConstant;
  yConstraint.constant = newYConstraintConstant;
  [view setNeedsLayout];

我承认这可能不是您所希望的一切,因为通常您想要修改 anchorPoint 的唯一原因是设置一个变换。这将需要一个更复杂的函数来更新布局约束以反映 所有 可能由 transform 属性本身引起的帧更改。这很棘手,因为变换可以对帧做很多事情。缩放或旋转变换会使框架变大,因此我们需要更新任何宽度或高度约束等。

如果您只是将变换用于临时动画,那么上述内容可能就足够了,因为我认为自动布局不会阻止飞行中的动画呈现代表纯粹暂时违反约束的图像。

【讨论】:

不幸的是,我正在使用转换。设置位置很好,因为每次布局视图时都会调用该方法,因此它不会被破坏。我在想覆盖 layoutRect 可能是一个更好的解决方案(在您之前的一个答案中提到),但我还没有尝试过。 顺便说一下,这是我一直在使用的测试台。如果有人能解决这个问题那就太好了:github.com/algal/AutolayoutAnchorPointTestRig 这应该是公认的答案。 @matt 的回答甚至与锚点无关。【参考方案5】:

tl:dr:您可以为其中一个约束创建一个出口,以便可以将其删除并重新添加。


我创建了一个新项目并在中心添加了一个固定大小的视图。约束如下图所示。

接下来,我为要旋转的视图和中心 x 对齐约束添加了一个出口。

@property (weak, nonatomic) IBOutlet UIView *rotatingView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *xAlignmentContstraint;

稍后在viewDidAppear我计算新的锚点

UIView *view = self.rotatingView;

CGPoint rotationPoint = // The point I'm rotating around... (only X differs)
CGPoint anchorPoint = CGPointMake((rotationPoint.x-CGRectGetMinX(view.frame))/CGRectGetWidth(view.frame),
                                  (rotationPoint.y-CGRectGetMinY(view.frame))/CGRectGetHeight(view.bounds));

CGFloat xCenterDifference = rotationPoint.x-CGRectGetMidX(view.frame);

view.layer.anchorPoint = anchorPoint;

然后我删除我有出口的约束,创建一个新的偏移并重新添加它。之后,我告诉具有更改约束的视图它需要更新约束。

[self.view removeConstraint:self.xAlignmentContstraint];
self.xAlignmentContstraint = [NSLayoutConstraint constraintWithItem:self.rotatingView
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1.0
                                                           constant:xDiff];
[self.view addConstraint:self.xAlignmentContstraint];
[self.view needsUpdateConstraints];

最后我只是将旋转动画添加到旋转视图中。

CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotate.toValue = @(-M_PI_2);
rotate.autoreverses = YES;
rotate.repeatCount = INFINITY;
rotate.duration = 1.0;
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

[view.layer addAnimation:rotate forKey:@"myRotationAnimation"];

即使在旋转设备或以其他方式导致它更新约束时,旋转层看起来也保持居中(它应该如此)。新约束和更改后的锚点在视觉上相互抵消。

【讨论】:

这适用于我的具体情况,看起来不可能有一个好的通用解决方案。【参考方案6】:

我目前的解决方案是手动调整图层在viewDidLayoutSubviews 中的位置。此代码也可以在layoutSubviews 中用于视图子类,但在我的情况下,我的视图是视图控制器内的***视图,因此这意味着我不必创建 UIView 子类。

这似乎太费劲了,所以欢迎其他答案。

-(void)viewDidLayoutSubviews

    for (UIView *view in self.view.subviews)
    
        CGPoint anchorPoint = view.layer.anchorPoint;
        // We're only interested in views with a non-standard anchor point
        if (!CGPointEqualToPoint(CGPointMake(0.5, 0.5),anchorPoint))
        
            CGFloat xDifference = anchorPoint.x - 0.5;
            CGFloat yDifference = anchorPoint.y - 0.5;
            CGPoint currentPosition = view.layer.position;

            // Use transforms if we can, otherwise manually calculate the frame change
            // Assuming a transform is in use since we are changing the anchor point. 
            if (CATransform3DIsAffine(view.layer.transform))
            
                CGAffineTransform current = CATransform3DGetAffineTransform(view.layer.transform);
                CGAffineTransform invert = CGAffineTransformInvert(current);
                currentPosition = CGPointApplyAffineTransform(currentPosition, invert);
                currentPosition.x += (view.bounds.size.width * xDifference);
                currentPosition.y += (view.bounds.size.height * yDifference);
                currentPosition = CGPointApplyAffineTransform(currentPosition, current);
            
            else
            
                CGFloat transformXRatio = view.bounds.size.width / view.frame.size.width;

                if (xDifference < 0)
                    transformXRatio = 1.0/transformXRatio;

                CGFloat transformYRatio = view.bounds.size.height / view.frame.size.height;
                if (yDifference < 0)
                    transformYRatio = 1.0/transformYRatio;

                currentPosition.x += (view.bounds.size.width * xDifference) * transformXRatio;
                currentPosition.y += (view.bounds.size.height * yDifference) * transformYRatio;
            
            view.layer.position = currentPosition;
        

    

【讨论】:

【参考方案7】:

启发了我的 matt 的回答,我决定尝试不同的方法。可以使用适当应用约束的容器视图。然后可以将具有修改后的锚点的视图放置在容器视图中,使用自动调整大小的蒙版和显式框架设置,就像在糟糕的过去一样。

不管怎样,这对我来说是一种享受。视图在 viewDidLoad 中设置:

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIView *redView = [UIView new];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    self.redView = redView;

    UIView *greenView = [UIView new];
    greenView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    greenView.layer.anchorPoint = CGPointMake(1.0, 0.5);
    greenView.frame = redView.bounds;
    greenView.backgroundColor = [UIColor greenColor];
    [redView addSubview:greenView];
    self.greenView = greenView;

    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = 0.005;
    self.redView.layer.sublayerTransform = perspective;

此时红色视图的帧为零并不重要,因为绿色视图上有自动调整大小的蒙版。

我在一个动作方法上添加了一个旋转变换,结果如下:

它似乎在设备旋转期间迷失了自己,所以我将它添加到 viewDidLayoutSubviews 方法中:

-(void)viewDidLayoutSubviews

    [super viewDidLayoutSubviews];
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    CATransform3D transform = self.greenView.layer.transform;
    self.greenView.layer.transform = CATransform3DIdentity;
    self.greenView.frame = self.redView.bounds;
    self.greenView.layer.transform = transform;
    [CATransaction commit];


【讨论】:

我想知道在你的情况下,让view.layer 一个人呆着,在view.layer 的子层中完成所有工作会不会更容易。换句话说,视图只是一个宿主,所有的绘图和子图层变换等等都是一个层次,不受约束的影响。 好的,受您的子视图解决方案的启发,我已将其添加到我的文章中!谢谢你让我在你的沙盒里玩……【参考方案8】:

我认为您使用该方法破坏了自动布局的目的。您确实提到宽度和右边缘取决于超级视图,那么为什么不沿着这条思路添加约束呢?

丢掉anchorPoint/transform范例并尝试:

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeRight
                             relatedBy:NSLayoutRelationEqual 
                                toItem:self.view 
                             attribute:NSLayoutAttributeWidth 
                            multiplier:1.0f
                              constant:-somePadding]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeWidth
                             relatedBy:NSLayoutRelationEqual 
                                toItem:someViewWeDependTheWidthOn
                             attribute:NSLayoutAttributeWidth 
                            multiplier:0.5f // because you want it to be half of someViewWeDependTheWidthOn
                              constant:-20.0f]]; // your 20pt offset from the left

NSLayoutAttributeRight 约束与anchorPoint = CGPointMake(1.0, 0.5) 完全相同,NSLayoutAttributeWidth 约束大致等同于您之前代码的NSLayoutAttributeLeft

【讨论】:

感谢您的回答,但我不能“失去锚点/转换范式”。我需要应用变换,并调整锚点以进行正确的变换。 为了进一步解释,在这种特定情况下,转换后的视图有时需要通过在其最右侧边缘沿 Y 轴旋转来折叠到屏幕中。因此,必须移动锚点。我也在寻找一个通用的解决方案。 当然你仍然可以保留anchorPoint,我的意思是你不应该用它来测量。 UIView 自动布局系统应该独立于 CALayer 转换。所以 UIView:layout, CALayer:appearance/animations 应该是,但不是。你真的试过这个吗?更改锚点会在自动布局完成其工作后 偏移图层的位置。您的解决方案不适用于修改后的锚点。 是的,我可以对带有约束的视图使用不同的锚点。您在viewDidLayoutSubviews 中的回答应该可以解决这个问题; position 总是与 anchorPoint 一起使用。我的回答仅仅展示了如何定义恒等变换的约束。【参考方案9】:

这个问题和答案启发我解决我自己的问题,使用自动布局和缩放,但使用滚动视图。我在 github 上创建了我的解决方案示例:

https://github.com/hansdesmedt/AutoLayout-scrollview-scale

这是一个 UIScrollView 的示例,它具有完全在 AutoLayout 中制作的自定义分页,并且可以通过长按和点击进行缩放 (CATransform3DMakeScale) 进行缩放。兼容 iOS 6 和 7。

【讨论】:

【参考方案10】:

这是一个很大的话题,我没有阅读所有的 cmets,但面临同样的问题。

我从 XIB 获得了带有自动布局的视图。我想更新它的变换属性。将视图嵌入到容器视图中并不能解决我的问题,因为自动布局在容器视图上表现得很奇怪。这就是为什么我刚刚添加了第二个容器视图来包含包含我的视图并对其应用转换的容器视图。

【讨论】:

【参考方案11】:

tl;dr 假设您将锚点更改为 (0, 0)。锚点现在位于左上角。每当您在自动布局中看到 center 一词时,您应该想到 top-left

当您调整锚点时,您只需更改 AutoLayout 的语义。自动布局不会干扰您的锚点,反之亦然。如果你不明白这一点,你会过得很糟糕


例子:

图 A. 无锚点修改

#Before changing anchor point to top-left
view.size == superview.size
view.center == superview.center

图 B. 锚点更改为左上角

view.layer.anchorPoint = CGPointMake(0, 0)
view.size == superview.size
view.center == superview.topLeft                <----- L0-0K, center is now top-left

图 A 和图 B 看起来完全一样。没有改变。只是 center 所指的定义发生了变化。

【讨论】:

这一切都很好,但没有回答当您的约束与中心无关时该怎么做的问题。【参考方案12】:

我有一个相对简单的案例,我需要将锚点设置为等于(0, 1)。显然,我能够使用容器视图并在其上镜像值(如(0, 1) -&gt; (1, 0))来实现此效果,因此生成的视图就像任何普通的(0.5, 0.5)

let scaledLabel = UILabel()
let container = UIView()

container.addSubview(scaledLabel)

// pin label to the edges of container with autolayout

scaledLabel.layer.anchorPoint = .init(x: 0, y: 1)
container.layer.anchorPoint = .init(x: 1, y: 0)

我不完全确定它如何与其他值一起使用,但它可能仍然有用

【讨论】:

以上是关于使用自动布局时,如何调整 CALayer 的锚点?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UITableViewCell 的附件按钮作为 Popover 的锚点

更新 CALayer 的旋转

ai里的锚点可以分为哪四种

锚点:= [akCenter]?

如何使用UITableViewCell附件Button作为Popover的锚点

HTML:使链接指向页面中间的锚点