当前位置: 首页 > 知识库问答 >
问题:

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

周威
2023-03-14

注:自提出这个问题以来,情况有所进展;请参见此处,了解最近的良好概述。

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

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

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

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(我希望从superview的左边缘插入的距离),即带有调整的定位点的视图。

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

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

共有3个答案

班凌
2023-03-14

我找到了一个简单的方法。它可以在iOS 8和iOS 9上运行。

与使用基于帧的布局时调整锚点类似:

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

使用“自动布局”调整视图的定位时,可以执行相同的操作,但要使用约束方式。当锚点从(0.5,0.5)更改为(1,0.5)时,layerView将向左移动,距离为视图宽度长度的一半,因此需要对此进行补偿。

我不理解问题中的限制。因此,假设您添加了一个相对于superView centerX的centerX约束,该约束具有一个常量:layerView。centerX=超级视图。centerX常量

layerView.layer.anchorPoint = CGPoint(1, 0.5)
let centerXConstraint = .....
centerXConstraint.constant = centerXConstraint.constant + layerView.bounds.size.width/2
乜裕
2023-03-14

我有一个类似的Isuue,刚刚从苹果的Autolayout团队那里得到回复。他们建议使用matt建议的容器视图方法,但他们创建了UIView的一个子类来覆盖LayoutSubView并在那里应用自定义布局代码,这很有魅力

文件如下所示,以便您可以直接从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

如您所见,它在第一次调用时抓住视图的中心点,并在进一步调用中重用该位置,以便相应地放置视图。这在某种意义上覆盖了自动布局代码,即它发生在[超级布局子视图]之后;其中包含自动布局代码。

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

步建茗
2023-03-14

[编辑:警告:接下来的整个讨论可能会过时,或者至少会被iOS 8严重缓解,iOS 8可能不再会在应用视图转换时错误地触发布局。]

Autolayout在视图变换中根本不起作用。据我所知,原因是您不应该弄乱具有变换(默认标识变换除外)的视图的框架,但这正是autolayout所做的。自动布局的工作方式是,在布局子视图(layoutSubviews)中,运行时快速遍历所有约束,并相应地设置所有视图的框架。

换句话说,约束不是魔术;它们只是一个待办事项清单<代码>布局子视图是完成待办事项列表的地方。它通过设置帧来实现。

我忍不住把这当成一个bug。如果将此变换应用于视图:

v.transform = CGAffineTransformMakeScale(0.5,0.5);

我希望看到视图的中心与之前相同,大小为原来的一半。但是根据它的限制,这可能根本不是我看到的。

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

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

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

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]];

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

上述两种解决方案的问题在于,我们失去了定位观点的约束优势。所以这里有一个解决方案。从一个不可见的视图开始,该视图的任务只是充当主体,然后使用约束对其进行定位。在其中,将真实视图作为子视图。使用约束在主体视图中定位子视图,但将这些约束限制为在应用变换时不会反击的约束。

下面是一个示例:

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

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

同时,在旋转设备时,主机视图上的约束将其保持在正确的位置。

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

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

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

尽管最终视图的大小没有变化,但仅仅设置它的变换就会导致布局发生,并且约束会使视图跳来跳去。(这感觉像个错误还是什么?)但是如果我们对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];
 类似资料:
  • 大家早上好,当显示键盘时,我有一个关于调整布局大小的小问题。 在清单中,我有调整调整大小,我也试图使用调整潘,但我有问题与滚动的回收器视图。 我的布局代码是: 谢谢,谁能帮我

  • 我想在正常情况下,当我打开一个Android对话框时,原始视图会变暗,我可以将视图聚焦在对话框上,关闭对话框后它会恢复。但是现在,我尝试通过使用XML创建一个自定义对话框。在这段时间里,原来的活动视图不会变暗,我怎么调整呢?

  • 我想在软键盘激活时调整版面的大小,如下所示: 前后: 在SO: 在显示软键盘时如何保持所有字段和文本可见 安卓软键盘出现时破坏布局 软键盘打开时调整布局 但问题和答案是相当模糊的,这里的问题更清楚地描述了我想要什么。 要求: 它应适用于任何屏幕大小的电话。 注意到“facebook”和“注册facebook”处的边距/填充空间前后发生了变化。 不涉及滚动视图。

  • 我有两个视图,我试图用自动布局调整大小/重新定位。 我设置了以下约束: 红色视图: 超级视图的顶部空间:0 落后和领先空间到超级视图:0 高度等于:100 蓝色视图: 顶部空间到红色视图:0 落后和领先空间到超级视图:0 高度等于:100 两个视图都是的子视图。蓝色视图有一个作为子视图(屏幕截图中未显示)。我想做的是更改红色视图的大小(带有动画),并让蓝色视图跟随该大小更改: 动画生效,红色视图的

  • 我必须在屏幕上显示一个带有多个“开关”控件iPhone弹出窗口。并分别通过打开/关闭操作在弹出窗口上添加和删除子视图。有关情况的更好说明,请参见下面 就像上面一样,当“添加邮件”开关为“ON”时,弹出视图必须再次增加高度,再添加两个子视图。最后看起来像这样, 就是这样。我正在通过我的应用程序使用自动布局,这是我感到困惑的地方。我知道我可以删除弹出窗口,每次都可以再删除一个新的弹出窗口,但这似乎是新

  • 当软键盘出现在屏幕上时,我需要软键盘和编辑文本之间正好有50dp的间隙。最终的输出会像这样 我怎样才能做到这一点?清单中的调整平移或调整调整大小并没有给我具体的差距。