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

2024-04-12

Note:自从提出这个问题以来,事情已经发生了变化;看here http://revealapp.com/blog/constraints-and-transforms.html以获得近期的良好概述。


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

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

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

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(我想要从超级视图的左边缘插入的距离)。

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

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


[EDIT: Warning:接下来的整个讨论可能会过时,或者至少会被 iOS 8 大大缓解,iOS 8 可能不再会在应用视图变换时犯下触发布局的错误。]

自动布局与视图变换

自动布局与视图变换根本不能很好地配合。据我所知,原因是您不应该弄乱具有变换(默认标识变换除外)的视图的框架 - 但这正是自动布局的作用。自动布局的工作方式是layoutSubviews运行时会冲破所有约束并相应地设置所有视图的框架。

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

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

v.transform = CGAffineTransformMakeScale(0.5,0.5);

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

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

解决方案 1:无限制

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

解决方案 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:改用图层变换

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

例如,这个简单的“throb”视图动画很可能在自动布局下崩溃:

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

尽管最终视图的大小没有改变,只是设置了它的大小transform导致布局发生,约束可以使视图跳跃。 (这感觉像是一个错误还是什么?)但是如果我们对 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];
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用自动布局时如何调整 CALayer 的锚点? 的相关文章

  • 如何在 swift 中以编程方式使用坐标打开地图应用程序?

    我想在地图应用程序中打开纬度和经度 我尝试了这段代码HERE https stackoverflow com questions 12504294 programmatically open maps app in ios 6 func g
  • 尝试注册 RCTBridgeModule 类 RCTFileReaderModule

    尝试为名称 FileReaderModule 注册 RCTBridgeModule 类 RCTFileReaderModule 但该名称已由类 FileReaderModule 注册 尝试使用命令react native run ios在i
  • IOS 上图像的加密/解密

    我们正在使用加密 解密和 UIIMAGE 如果我们加密和解密 UIIMAge 而不保存到 iphone 画廊中 它工作正常 但如果我们加密 保存到画廊中 将 加密的图像 加载到应用程序中 然后解密它效果不好 我们使用这个函数来加密 解密 保
  • 调用了 numberOfRowsInSection 但未调用 cellForRowAtIndexPath

    在我的表视图中节中的行数被调用两次但是cellForRowAtIndexPath不叫 我想在 tableView 中显示 Facebook 好友列表 如果 cellForRowAtIndexPath 调用我的问题就解决了 我在这里的数组中得
  • ArraySlice 中的 Swift [重复]

    这个问题在这里已经有答案了 在数组上使用 prefix 方法后 我得到了所谓的 arraySlice 我怎样才能将其转换为数组 我试图从 FacebookGraphApi 获取 Ints 然后请求前 3 个 前缀 3 并尝试将它们添加到新数
  • 在iOS中设置框架的原点

    我正在尝试以编程方式设置框架的原点 Method1 button frame origin y 100 方法二 CGRect frame button frame frame origin y 100 我尝试了方法 1 但它不起作用 显示错
  • 在 iOS 上使用 HEVC 编码器输出视频尺寸巨大

    我有一个项目 目前使用 H 264 编码器在 iOS 上录制视频 我想尝试在 iOS 11 中使用新的 HEVC 编码器来减小文件大小 但发现使用 HEVC 编码器会导致文件大小急剧膨胀 GitHub 上的一个项目显示了该问题 它使用 H
  • 当自定义子视图处理触摸时防止 UITableView 滚动

    在我的 iOS 应用程序中 有一个 UITableView 其中一个单元格中包含一个自定义子视图 该单元格是一个交互式视图 它处理触摸事件 touchesBegan touchesEnded touchesMoved 以更新自身 问题是 当
  • 在 Swift 中使用 commitEditingStyle 动态删除 UITable 部分

    我正在处理一个无法解决的问题 我有一个来自客户数据库数组的名称表 每个客户在其他数据成员中都有一个名称属性 我可以成功删除某个部分中的行 但我不能删除该部分 当该部分中的最后一行被删除时 该部分必须消失 I got NSInternalIn
  • 以编程方式向 UIButton 标签添加阴影

    我试图向按钮标签添加 1px 黑色阴影 但没有成功 我试过这个 self setTitleShadowOffset CGSizeMake 0 1 但我得到 请求非结构或联合中的成员 setTitleShadowOffset 任何建议都会很棒
  • 如何更改便携式 xamarin ios 项目中的启动屏幕?

    我正在使用便携式 xamarin 形式 其中项目是 IOS 项目 在 IOS 项目中 我想创建闪屏 我在 ios 项目属性中添加了 Iphone 启动图像和 iPad 启动图像 当我运行该应用程序时 它显示默认的启动屏幕 我还尝试从 inf
  • iOS:将观察者添加到 UIView 的frame.origin.y?

    我正在尝试监视 UIView 框架原点的变化值并对其做出反应 我的代码 cell bottomView addObserver self forKeyPath frame origin options NSKeyValueObserving
  • malloc:***错误:已释放对象的校验和不正确 - 对象可能在释放后被修改

    我的 iOS 应用程序有一个大问题 它有时会崩溃 而没有详细的调试错误 堆栈跟踪为空 这是堆栈跟踪中仅有的两行 UIApplicationMain 中的 符号存根 UIHostedTextServiceSession DismissText
  • iOS 11 浮动 TableView 标题

    有一个应用程序包含多个部分 展开 时每个部分有几行 折叠 时没有 每个部分都有一个部分标题 使用以下子类重用它们UITableViewHeaderFooterView等等 到目前为止一切顺利 然后在 iOS 11 中 我使用了可视化调试器
  • AFNetworking 上传图片

    我看过一些例子 但我认为我的问题可能出在 PHP 中 我正在尝试使用 AFNetworking 将图像从 iPhone 上传到服务器 这是我的 obj c 代码 IBAction uploadButtonClicked id sender
  • 如何从 Firebase 同步检索数据?

    我有两个集合 即用户和问题 根据使用 userId 登录的用户 我检索currQuestion价值来自users收藏 基于currQuestion值 我需要检索question来自 Firebase 的文档Questions收藏 我使用下面
  • 由于 2.23 导致 iOS 应用程序被拒绝 - iOS 数据存储指南

    以下是 Apple 关于拒绝的消息 2 23 应用程序必须遵循 iOS 数据存储指南 否则将被拒绝 2 23 详情 在启动和内容下载时 您的应用程序会存储 6 5 MB 这并不意味着 遵守 iOS 数据存储指南 下一步 请验证只有用户使用您
  • Xcode 在代码签名身份中看不到我的开发人员证书

    我续订了 IOS 开发人员证书 从钥匙串中删除了旧证书 然后单击了我的证书 钥匙串中的一切看起来都很正常 我有分发 开发人员 WWDC 证书 每个配置文件看起来都有效 并带有绿色标记 在组织器中的团队和配置文件部分下 但在代码签名身份下的
  • 选择 UITableViewCell 时 UIView 背景颜色消失

    我在界面生成器中构建了一个简单的 tableViewCell 它包含一个包含图像的 UIView 现在 当我选择单元格时 会显示默认的蓝色选择背景 但 UIView 的背景颜色消失了 我的 UITableViewCell 的实现文件没有做任
  • iOS 13 检查 CLLocationManager 的临时授权状态

    根据 WWDC 视频 https developer apple com videos play wwdc2019 705 https developer apple com videos play wwdc2019 705 当你要求 Al

随机推荐

  • 我应该在 HTML 中使用 % 或 'px'

    无论是 HTML XHTML 还是 HTML5 您都会发现到处都是令人讨厌的百分比 然而 我看到很多网站都不敢靠近它们 然而大学总是鼓励我使用它们 那么我应该使用哪个 哪一个会带来更好的网站设计 为什么 我知道要避免使用高度 尽管如果我想使
  • 使用锚点提交表单安全吗?

    我在某处读到 使用锚标记提交表单不太安全 所以这就是我的问题 使用锚标记而不是安全吗
  • Curl 同时下载和上传同一文件

    不确定是否可能 但我一直在尝试使用curl 从 HTTP 位置下载文件并将其输出到 FTP 服务器上 如果这实际上可能的话 我真的很希望得到一些帮助 curl http example com down curl T ftp mysite
  • 捕获 Flask API 中引发的自定义异常。引发的所有异常最终都会出现 500 错误 [重复]

    这个问题在这里已经有答案了 我希望能够在 API 中引发验证和其他异常 并在包装 视图中捕获它们 该视图将以 JSON 形式返回错误消息 我想我可以使用这样的东西 例外 class APIException Exception def in
  • AWS 批处理始终为每个作业启动新的 ec2 实例

    我已经设置了一个批处理环境 托管计算环境 作业队列 职位定义 实际工作 docker 容器 执行大量视频编码 因此占用了大部分 CPU 该过程本身需要几分钟 初始化所有编码器大约需要 5 分钟 理想情况下 我希望每个实例执行一项作业 这样编
  • 可以使用 OnDeserializedAttribute 代替 IDeserializationCallback 接口吗?

    正如 MSDN 所说here http msdn microsoft com en us library system runtime serialization ondeserializedattribute aspx 它可以 但我花了
  • 与 JPA OneToMany 映射的只读关联

    我有一个与另一个实体关联的事务实体 因此在案例中不应更新关联实体 例如 案例 gt 用户 案例由用户拥有 反之 用户可以拥有许多关联的案例 使用 OneToMany 和 JoinColumn JPA 注释来映射关联 我还尝试将 User 实
  • 如何从外部资源将库连接到智能合约?

    pragma solidity 0 4 15 import ERC20 sol import SafeMath sol 如何连接安全数学 sol来自外部 非本地的 资源 虽然詹姆斯的答案是有效的 但我不建议从在线存储库链接合同的依赖项 这是
  • 如何使用 Spring Security 为特定端点添加 HTTP 基本身份验证?

    我有一个带有 Spring Security 的 Spring Boot 应用程序 一个新的端点 health进行配置 以便可以通过基本 HTTP 身份验证进行访问 目前的HttpSecurity配置如下 Override protecte
  • woocommerce 显示类别/子类别/产品

    有没有办法在 woocommerce 中显示主要类别及其子类别及其产品 php 还是简码 我尝试过一些条件格式 但没有任何结果 您有两个默认的短代码可用于显示产品类别 定义了特定的父类别 以显示子类别 和特定类别中包含的产品 要显示顶级类别
  • 在 Vim 中轻松地将函数参数重新格式化为多行

    特别是在编辑旧版 C 代码时 我经常发现自己手动重新格式化如下内容 SomeObject doSomething firstType argumentOne secondType argumentTwo thirdType argument
  • ejabberd如何编译新模块

    Here http www ejabberd im node 2872我找到了代码 erlc I ejabberd 2 1 13 lib ejabberd 2 1 13 include pa ejabberd 2 1 13 lib ejab
  • 子进程 popen stdout 锁定?

    您好 在使用 subprocess Popen 时 读取标准输出时遇到一些问题 daniel desktop python V Python 2 7 3 这是代码 注释代码是我尝试过的一些事情 import subprocess RUN h
  • 通过浏览器调用WCF服务方法

    我有一个使用基本 http 绑定的 WCF 服务 如何通过浏览器调用其操作 方法 您需要将 WebGetAttribute 添加到您的方法中 如下例所示 OperationContract WebGet UriTemplate places
  • 当我单击搜索按钮时,防止 ProgressDialog 被关闭(Android)

    在长时间运行的操作中 我显示了一个弹出对话框 由ProgressDialog以防止其他操作发生 我已将其设置为不可取消setCancelable false 所以我无法使用后退按钮关闭它 但令人惊讶的是 搜索 硬件按钮会关闭该对话框 更准确
  • 如何确定现有应用程序的安装范围?

    我有一个基于的安装程序WixUI Advanced允许用户选择安装范围 每个用户或机器范围 升级时 安装了较低版本的现有应用程序 我想隐藏安装范围屏幕并自动选择他们上次选择的安装范围 如何判断先前安装使用的安装范围 Edit 查看我的 MS
  • Android 代码从 ContentProvider 类而不是 Main 类开始

    昨天我发布了一个类似的问题 关于为什么我的代码从我的内容提供程序类而不是主类开始 我收到了一些反馈 我已经更新了这些反馈 但问题仍然存在 代码从 ContentProvider 类而不是主类开始班级 我已经使用调试器运行了代码 令人费解的是
  • 从字符串中过滤非数字

    仅使用快速代码 我无法弄清楚如何获取 555 555 5555 并仅返回数值并获得 5555555555 我需要删除所有括号 空格和破折号 我能找到的唯一例子是 Objective C 中的 它们似乎都使用 trim 方法 看起来好像 sw
  • 使用 Apple 登录 - Ionic 3

    我正在尝试使用以下插件和包装器在我的 ionic 3 项目上实现苹果登录 ionic cordova plugin add cordova plugin sign in with apple npm i save ionic native
  • 使用自动布局时如何调整 CALayer 的锚点?

    Note 自从提出这个问题以来 事情已经发生了变化 看here http revealapp com blog constraints and transforms html以获得近期的良好概述 在自动布局之前 您可以通过存储框架 设置锚点