gpt4 book ai didi

swift - 使用 CAGradientLayer 旋转 UIControl 无法正确更新 Swift

转载 作者:搜寻专家 更新时间:2023-10-31 22:04:05 25 4
gpt4 key购买 nike

我没有使用普通按钮,而是将 UIControl 子类化因为我需要给它添加一个渐变。我还有一种方法可以添加阴影和事件指示器(在下图中不可见)作为有状态按钮,以在(例如)进行 API 调用时阻止用户敲击按钮。

试图获得 UIControl 真的很棘手旋转,为了能够做到这一点,我将阴影作为单独的 View 添加到包含 UIControl 的容器 View 中所以可以添加阴影。

现在的问题是控件的行为不像旋转 View - 让我向您展示上下文的屏幕抓取: enter image description here

这是中间旋转,但肉眼几乎可见 - 图像显示渐变是蓝色长度的 75% UIView在图像中。

https://github.com/stevencurtis/statefulbutton

为了执行此轮换,我删除了 shadowview然后把gradient frame的frame改成它的bounds,就是这个问题。

func viewRotated() {
CATransaction.setDisableActions(true)

shadowView!.removeFromSuperview()
shadowView!.frame = self.frame
shadowView!.layer.masksToBounds = false
shadowView!.layer.shadowOffset = CGSize(width: 0, height: 3)
shadowView!.layer.shadowRadius = 3
shadowView!.layer.shadowOpacity = 0.3
shadowView!.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 20, height: 20)).cgPath
shadowView!.layer.shouldRasterize = true
shadowView!.layer.rasterizationScale = UIScreen.main.scale

self.gradientViewLayer.frame = self.bounds
self.selectedViewLayer.frame = self.bounds

CATransaction.commit()

self.insertSubview(shadowView!, at: 0)

}

所以这个旋转方法是通过父 View Controller 调用的:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { context in
context.viewController(forKey: UITransitionContextViewControllerKey.from)
//inform the loginButton that it is being rotated
self.loginButton.viewRotated()
}, completion: { context in
// can call here when completed the transition
})
}

我知道这就是问题所在,而且我想这不是在正确的时间以与 UIView 相同的方式行事。 .现在的问题是我已经尝试了很多方法来让它工作,但我的最佳解决方案(上图)并不完全正确。

建议使用 UIButton 没有帮助,为渐变使用图像(请不要建议使用渐变图像作为 UIButton 的背景,我试过这个)或第三方库。这是我的作品,它可以正常工作,但我不能接受,我想让它像通常的 View 一样工作(或者至少知道为什么不可以)。我也尝试了上面的其他解决方案,并选择了我自己的 UIControl .我知道如果有 API 调用我可以锁定 View ,或者使用其他方式阻止用户多次按下按钮。我正在尝试修复我的解决方案,而不是发明解决此问题的方法 CAGradientLayer .

问题:我需要做一个UIControlViewCAGradientLayer作为背景以与 UIView 相同的方式旋转,并且不会出现上图中显示的问题。

完整示例: https://github.com/stevencurtis/statefulbutton

最佳答案

这是工作代码:

https://gist.github.com/alldne/22d340b36613ae5870b3472fa1c64654

这些是我对您的代码的建议:

1。设置大小和子图层位置的适当位置

View (即按钮)的大小是在布局完成后确定的。你应该做的只是在布局后设置适当的子层大小。所以我建议你在 layoutSubviews 中设置渐变子图层的大小和位置。

    override func layoutSubviews() {
super.layoutSubviews()

let center = CGPoint(x: self.bounds.width / 2, y: self.bounds.height / 2)
selectedViewLayer.bounds = self.bounds
selectedViewLayer.position = center
gradientViewLayer.bounds = self.bounds
gradientViewLayer.position = center
}

2。您不需要使用额外的 View 来绘制阴影

删除 shadowView 并只设置图层属性:

layer.shadowOffset = CGSize(width: 0, height: 3)
layer.shadowRadius = 3
layer.shadowOpacity = 0.3
layer.shadowColor = UIColor.black.cgColor
clipsToBounds = false

如果你必须使用额外的 View 来绘制阴影,那么你可以在 init() 中添加一次 View ,并在 layoutSubviews 中设置合适的大小和位置,或者您可以通过编程方式为 super View 设置自动布局约束。

3。动画时长&定时功能

设置合适的尺寸后,渐变图层和容器 View 的动画不能很好地同步。

似乎是:

  • 在旋转过渡期间,协调器(UIViewControllerTransitionCoordinator) 有自己的过渡持续时间和缓动函数。
  • 并且持续时间和缓动功能会自动应用于所有 subview (UIView)。
  • 但是,如果没有关联的 UIView,这些值将不会应用于 CALayer。因此,它使用 CoreAnimation 的默认计时函数和持续时间。

要同步动画,请明确设置动画持续时间和计时函数,如下所示:

class ViewController: UIViewController {
...

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
CATransaction.setAnimationDuration(coordinator.transitionDuration)
CATransaction.setAnimationTimingFunction(coordinator.completionCurve.timingFunction)
}

...
}

// Swift 4
extension UIView.AnimationCurve {
var timingFunction: CAMediaTimingFunction {
let functionName: CAMediaTimingFunctionName
switch self {
case .easeIn:
functionName = kCAMediaTimingFunctionEaseIn as CAMediaTimingFunctionName
case .easeInOut:
functionName = kCAMediaTimingFunctionEaseInEaseOut as CAMediaTimingFunctionName
case .easeOut:
functionName = kCAMediaTimingFunctionEaseOut as CAMediaTimingFunctionName
case .linear:
functionName = kCAMediaTimingFunctionLinear as CAMediaTimingFunctionName
}
return CAMediaTimingFunction(name: functionName as String)
}
}

关于swift - 使用 CAGradientLayer 旋转 UIControl 无法正确更新 Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55609844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com