- 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/
IO 设备如何知道属于它的内存中的值在memory mapped IO 中发生了变化? ? 例如,假设内存地址 0 专用于保存 VGA 设备的背景颜色。当我们更改 memory[0] 中的值时,VGA
我目前正在开发一个使用Facebook sdk登录(通过FBLoginView)的iOS应用。 一切正常,除了那些拥有较旧版本的facebook的人。 当他们按下“使用Facebook登录”按钮时,他
假设我有: this - is an - example - with some - dashesNSRange将使用`rangeOfString:@“-”拾取“-”的第一个实例,但是如果我只想要最后
Card.io SDK提供以下详细信息: 卡号,有效期,月份,年份,CVV和邮政编码。 如何从此SDK获取国家名称。 - (void)userDidProvideCreditCardInfo:(Car
iOS 应用程序如何从网络服务下载图片并在安装过程中将它们安装到用户的 iOS 设备上?可能吗? 最佳答案 您无法控制应用在用户设备上的安装,因此无法在安装过程中下载其他数据。 只需在安装后首次启动应
我曾经开发过一款企业版 iOS 产品,我们公司曾将其出售给大型企业,供他们的员工使用。 该应用程序通过 AppStore 提供,企业用户获得了公司特定的配置文件(包含应用程序配置文件)以启用他们有权使
我正在尝试将 Card.io SDK 集成到我的 iOS 应用程序中。我想为 CardIO ui 做一个简单的本地化,如更改取消按钮标题或“在此保留信用卡”提示文本。 我在 github 上找到了这个
我正在使用 CardIOView 和 CardIOViewDelegate 类,没有可以设置为 YES 的 BOOL 来扫描 collectCardholderName。我可以看到它在 CardIOP
我有一个集成了通话工具包的 voip 应用程序。每次我从我的 voip 应用程序调用时,都会在 native 电话应用程序中创建一个新的最近通话记录。我在 voip 应用程序中也有自定义联系人(电话应
iOS 应用程序如何知道应用程序打开时屏幕上是否已经有键盘?应用程序运行后,它可以接收键盘显示/隐藏通知。但是,如果应用程序在分屏模式下作为辅助应用程序打开,而主应用程序已经显示键盘,则辅助应用程序不
我在模拟器中收到以下错误: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
如 Apple 文档所示,可以通过 EAAccessory Framework 与经过认证的配件(由 Apple 认证)进行通信。但是我有点困惑,因为一些帖子告诉我它也可以通过 CoreBluetoo
尽管现在的调试器已经很不错了,但有时找出应用程序中正在发生的事情的最好方法仍然是古老的 NSLog。当您连接到计算机时,这样做很容易; Xcode 会帮助弹出日志查看器面板,然后就可以了。当您不在办公
在我的 iOS 应用程序中,我定义了一些兴趣点。其中一些有一个 Kontakt.io 信标的名称,它绑定(bind)到一个特定的 PoI(我的意思是通常贴在信标标签上的名称)。现在我想在附近发现信标,
我正在为警报提示创建一个 trigger.io 插件。尝试从警报提示返回数据。这是我的代码: // Prompt + (void)show_prompt:(ForgeTask*)task{
您好,我是 Apple iOS 的新手。我阅读并搜索了很多关于推送通知的文章,但我没有发现任何关于 APNS 从 io4 到 ios 6 的新更新的信息。任何人都可以向我提供 APNS 如何在 ios
UITabBar 的高度似乎在 iOS 7 和 8/9/10/11 之间发生了变化。我发布这个问题是为了让其他人轻松找到答案。 那么:在 iPhone 和 iPad 上的 iOS 8/9/10/11
我想我可以针对不同的 iOS 版本使用不同的 Storyboard。 由于 UI 的差异,我将创建下一个 Storyboard: Main_iPhone.storyboard Main_iPad.st
我正在写一些东西,我将使用设备的 iTunes 库中的一部分音轨来覆盖 2 个视频的组合,例如: AVMutableComposition* mixComposition = [[AVMutableC
我创建了一个简单的 iOS 程序,可以顺利编译并在 iPad 模拟器上运行良好。当我告诉 XCode 4 使用我连接的 iPad 设备时,无法编译相同的程序。问题似乎是当我尝试使用附加的 iPad 时
我是一名优秀的程序员,十分优秀!