- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我有一个子类 UIView,我们可以调用它 CircleView
. CircleView 自动将角半径设置为其宽度的一半,以便它成为一个圆。
问题是当“CircleView”被 AutoLayout 约束调整大小时......例如 关于设备旋转 ...在调整大小之前它会严重扭曲,因为“cornerRadius”属性必须 catch ,并且操作系统只向 View 的框架发送一个“边界”更改。
我想知道是否有人有一个好的、清晰的策略来以在这种情况下不会扭曲的方式实现“CircleView”,但仍将其内容屏蔽为圆形,并允许在所述 UIView 周围存在边框。
最佳答案
更新:如果您的部署目标是 iOS 11 或更高版本:
从 iOS 11 开始,UIKit 将动画 cornerRadius
如果您在动画块内更新它。只需设置您的 View layer.cornerRadius
在 UIView
动画块,或者(为了处理界面方向变化),在 layoutSubviews
中设置它或 viewDidLayoutSubviews
.
原文:如果您的部署目标早于 iOS 11:
所以你想要这个:
(我打开了调试 > 慢速动画以使平滑度更容易看到。)
旁白,随意跳过这一段:事实证明这比应该的要困难得多,因为 iOS SDK 并没有以方便的方式提供自转动画的参数(持续时间、时间曲线)。你可以(我认为)通过覆盖 -viewWillTransitionToSize:withTransitionCoordinator:
来获得它们。在您的 View Controller 上调用 -animateAlongsideTransition:completion:
在转换协调器上,并在您传递的回调中,获取 transitionDuration
和 completionCurve
来自 UIViewControllerTransitionCoordinatorContext
.然后您需要将该信息传递给您的 CircleView
, 必须保存它(因为它还没有调整大小!)稍后它收到 layoutSubviews
,它可以用它来创建一个 CABasicAnimation
为 cornerRadius
使用那些保存的动画参数。并且不要在时不小心创建动画不是 动画调整大小... 旁白结束。
哇,这听起来像是大量的工作,您必须涉及到 View Controller 。这是另一种完全在 CircleView
内部实现的方法.它现在可以工作(在 iOS 9 中),但我不能保证它将来总是可以工作,因为它做出了两个理论上可能在 future 错误的假设。
这是方法:覆盖 -actionForLayer:forKey:
在 CircleView
返回一个 Action ,当运行时,为 cornerRadius
安装动画.
这是两个假设:
bounds.origin
和 bounds.size
获得单独的动画。 (现在确实如此,但据推测, future 的 iOS 可以为 bounds
使用单个动画。如果没有找到 bounds
动画,检查 bounds.size
动画就很容易了。)bounds.size
在 Core Animation 请求 cornerRadius
之前将动画添加到层行动。 cornerRadius
时行动,我们可以得到
bounds.size
从图层中创建动画,复制它,然后修改副本以制作动画
cornerRadius
反而。副本具有与原件相同的动画参数(除非我们修改它们),因此它具有正确的持续时间和时序曲线。
CircleView
的开始:
class CircleView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}
private func updateCornerRadius() {
layer.cornerRadius = min(bounds.width, bounds.height) / 2
}
layoutSubviews
之前设置的。 ,因此在我们更新
cornerRadius
之前.这就是为什么
bounds.size
动画安装在
cornerRadius
之前请求动画。每个属性的动画都安装在属性的 setter 中。
cornerRadius
, Core Animation 向我们索要
CAAction
运行它:
override func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == "cornerRadius" {
if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
let animation = boundsAnimation.copy() as! CABasicAnimation
animation.keyPath = "cornerRadius"
let action = Action()
action.pendingAnimation = animation
action.priorCornerRadius = layer.cornerRadius
return action
}
}
return super.action(for: layer, forKey: event)
}
cornerRadius
采取行动,我们寻找一个
CABasicAnimation
在
bounds.size
.如果找到了,就复制,把key path改成
cornerRadius
,并将其保存在自定义
CAAction
中(类
Action
,我将在下面展示)。我们还保存了
cornerRadius
的当前值属性,因为 Core Animation 调用
actionForLayer:forKey:
之前 更新属性。
actionForLayer:forKey:
返回,Core Animation 更新了
cornerRadius
层的属性。然后它通过发送
runActionForKey:object:arguments:
来运行操作. Action 的工作是安装任何合适的动画。这是
CAAction
的自定义子类,我嵌套在
CircleView
:
private class Action: NSObject, CAAction {
var pendingAnimation: CABasicAnimation?
var priorCornerRadius: CGFloat = 0
public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
if pendingAnimation.isAdditive {
pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
pendingAnimation.toValue = 0
} else {
pendingAnimation.fromValue = priorCornerRadius
pendingAnimation.toValue = layer.cornerRadius
}
layer.add(pendingAnimation, forKey: "cornerRadius")
}
}
}
} // end of CircleView
runActionForKey:object:arguments:
方法设置
fromValue
和
toValue
动画的属性,然后将动画添加到图层。有一个复杂的问题:UIKit 使用“附加”动画,因为如果您在早期动画仍在运行时在属性上启动另一个动画,它们会更好地工作。所以我们的行动会检查这一点。
fromValue
到新旧圆角半径的差异,并设置
toValue
到零。由于层的
cornerRadius
属性在动画运行时已经更新,添加
fromValue
在动画开始时使它看起来像旧的圆角半径,并添加
toValue
动画末尾的零使它看起来像新的角半径。
fromValue
和
toValue
以明显的方式。
import UIKit
class CircleView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}
private func updateCornerRadius() {
layer.cornerRadius = min(bounds.width, bounds.height) / 2
}
override func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == "cornerRadius" {
if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
let animation = boundsAnimation.copy() as! CABasicAnimation
animation.keyPath = "cornerRadius"
let action = Action()
action.pendingAnimation = animation
action.priorCornerRadius = layer.cornerRadius
return action
}
}
return super.action(for: layer, forKey: event)
}
private class Action: NSObject, CAAction {
var pendingAnimation: CABasicAnimation?
var priorCornerRadius: CGFloat = 0
public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
if pendingAnimation.isAdditive {
pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
pendingAnimation.toValue = 0
} else {
pendingAnimation.fromValue = priorCornerRadius
pendingAnimation.toValue = layer.cornerRadius
}
layer.add(pendingAnimation, forKey: "cornerRadius")
}
}
}
} // end of CircleView
关于ios - 使用 AutoLayout 调整圆形(圆形)UIView 的大小...如何在调整大小动画期间为cornerRadius 设置动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35713244/
这个问题在这里已经有了答案: C sizeof a passed array [duplicate] (7 个回答) 8年前关闭。 在一个函数中,我声明了一个数组: int char_count_ar
简而言之,文件系统如何与 block 设备通信? 最佳答案 我对 block 大小不太了解。我认为 ext4(Linux)的文件系统的 block 大小是 4KB,考虑到现代处理器的页面大小(4KB)
我知道 tinyint(1) 和 tinyint(2) 具有相同的存储空间范围。 唯一的区别是显示宽度不同。这是否意味着 tinyint(1) 将存储所有类型的整数但只正确显示 0 到 9 的范围?而
今晚我已经研究了以下代码几个小时,但我只是摸不着头脑。 当使用函数从标准输入填充数组时,我不断收到“大小 8 的无效写入”和“大小 8 的无效读取”。 如有任何帮助,我们将不胜感激...我知道 Sta
我有一个 valgrind 错误,我不知道如何摆脱它们: ==5685== Invalid read of size 8 ==5685== at 0x4008A1: main (in /home
我对 Hadoop 的概念有点困惑。 Hadoop block 大小、拆分大小和 block 大小 之间有什么区别? 提前致谢。 最佳答案 block 大小和 block 大小相同。 拆分大小 可能与
我想不出一个好的标题,所以希望可以。 我正在做的是创建一个离线 HTML5 webapp。 “出于某些原因”我不希望将某些文件放在缓存 list 中,而是希望将内容放在 localStorage 中。
无法将 xamarin apk 大小减少到 80 MB 以下,已执行以下操作: 启用混淆器 配置:发布 平台:事件(任何 CPU)。 启用 Multi-Dex:true 启用开发人员检测(调试和分析)
我正在开发一个程序,需要将大量 csv 文件(数千个)加载到数组中。 csv 文件的尺寸为 45x100,我想创建一个尺寸为 nx45x100 的 3-d 数组。目前,我使用 pd.read_csv(
Hello World 示例的 React Native APK 大小约为 20M (in recent versions),因为支持不同的硬件架构(ARMv7、ARMv8、X86 等),而同一应用程
我有一个包含 n 个十进制元素的列表,其中每个元素都是两个字节长。 可以说: x = [9000 , 5000 , 2000 , 400] 这个想法是将每个元素拆分为 MSB 和 LSB 并将其存储在
如何设置 GtKTextView 的大小?我想我不能使用 gtk_widget_set_usize。 最佳答案 您不能直接控制小部件的大小,而是由其容器完成。您可以使用 gtk_widget_set_
这个问题在这里已经有了答案: c++ sizeof() of a class with functions (7 个答案) 关闭 5 年前。 结果是 12。 foobar 函数存储在内存中的什么位置
当我在 ffmpeg(或任何其他程序)中使用这样的命令时: ffmpeg -i input.mp4 image%d.jpg 所有图像的组合文件大小总是比视频本身大。我尝试减少每秒帧数、降低压缩设置、模
我是 clojurescript 的新手。 高级编译后出现“77 KB”的javascript文件是否正常? 我有一个 clojurescript 文件: 我正在使用 leinigen: lein c
我想要一个 QPixmap尺寸为 50 x 50。 我试过 : QPixmap watermark(QSize(50,50)); watermark.load(":/icoMenu/preparati
我正在尝试从一篇研究论文中重新创建一个 cnn,但我对深度学习还是个新手。 我得到了一个大小为 32x32x7 的 3d 补丁。我首先想执行一个大小为 3x3 的卷积,具有 32 个特征和步幅为 2。
我一直在尝试调整 View Controller 内的 View 大小,但到目前为止没有运气。基本上,我的 View 最底部有一个按钮,当方向从纵向更改为横向时,该按钮不再可见,因为它现在太靠下了。
如何使用此功能检查图像的尺寸?我只是想在上传之前检查一下... $("#LINK_UPLOAD_PHOTO").submit(function () { var form = $(this);
我用 C++ 完成了这个,因为你可以通过引用传递参数。我无法弄清楚如何在 JavaScript 中执行此操作。我的代码需要更改什么?我的输出是1 this.sizeOfBst = function()
我是一名优秀的程序员,十分优秀!