- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如果有人想尝试此代码,您只需 c+p 文件即可运行
实际上我在下面的代码中有 2 个问题。
1- 我有一个 Timer
和一个 CABasicAnimation
,它们都在触发 longPressGesture
时运行。计时器是 15 秒,一旦我注意到这个问题,我决定用它来为动画计时。发生的事情是动画在计时器完成之前完成。动画将在计时器结束前和 CATransaction.setCompletionBlock()
和 animationDidStop(_:finished)
被调用前 1 秒左右关闭/到达其端点。基本上动画结束得太早了。
2- 如果我将手指从按钮上移开,将调用 longPressGesture 的 .cancelled/.ended
并通过 pauseShapeLayerAnimation 在
。这是我发现真正停止动画的唯一方法。当我再次长按按钮时,我从头开始重新启动计时器和动画。问题是因为 invalidateTimer
中暂停计时器()pauseShapeLayerAnimation()
也会在计时器停止时调用(达到 15 秒)CATransaction.setCompletionBlock()
永远不会 animationDidStop(_:finished)
调用。只有当我将手指放回按钮上时,它们才会被调用。
更新 我通过检查 invalidateTimer 函数中的秒数是否为 != 0 解决了第二个问题
import UIKit
class ViewController: UIViewController {
//MARK:- UIElements
fileprivate lazy var roundButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.blue
return button
}()
fileprivate lazy var timerLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.monospacedDigitSystemFont(ofSize: 22, weight: .medium)
label.textColor = UIColor.black
label.text = initialStrForTimerLabel
label.textAlignment = .center
return label
}()
fileprivate lazy var box: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .brown
return view
}()
//MARK:- Properties
fileprivate let shapeLayer = CAShapeLayer()
fileprivate let bgShapeLayer = CAShapeLayer()
fileprivate var basicAnimation: CABasicAnimation!
fileprivate var maxTimeInSecs = 15
fileprivate lazy var seconds = maxTimeInSecs
fileprivate var milliseconds = 0
fileprivate lazy var timerStr = initialStrForTimerLabel
fileprivate lazy var initialStrForTimerLabel = "\(maxTimeInSecs).0"
fileprivate weak var timer: Timer?
//MARK:- View Controller Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setAnchors()
setGestures()
}
fileprivate var wereCAShapeLayersAdded = false
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if !wereCAShapeLayersAdded {
wereCAShapeLayersAdded = true
roundButton.layer.cornerRadius = roundButton.frame.width / 2
addBothCAShapeLayersToRoundButton()
}
}
//MARK:- Animation Methods
fileprivate func addBothCAShapeLayersToRoundButton() {
bgShapeLayer.frame = box.bounds
bgShapeLayer.path = UIBezierPath(rect: box.bounds).cgPath
bgShapeLayer.strokeColor = UIColor.lightGray.cgColor
bgShapeLayer.fillColor = UIColor.clear.cgColor
bgShapeLayer.lineWidth = 6
box.layer.addSublayer(bgShapeLayer)
box.layer.insertSublayer(bgShapeLayer, at: 0)
shapeLayer.frame = box.bounds
shapeLayer.path = UIBezierPath(rect: box.bounds).cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 6
shapeLayer.lineCap = .round
shapeLayer.strokeEnd = 0
box.layer.addSublayer(shapeLayer)
}
fileprivate var isBasicAnimationAnimating = false
fileprivate func addProgressAnimation() {
CATransaction.begin()
basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
removeAnimation()
if shapeLayer.timeOffset > 0.0 {
shapeLayer.speed = 1.0
shapeLayer.timeOffset = 0.0
}
basicAnimation.delegate = self
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
basicAnimation.fromValue = 0
basicAnimation.toValue = 1
basicAnimation.duration = CFTimeInterval(seconds)
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.isRemovedOnCompletion = false
CATransaction.setCompletionBlock {
print("CATransaction completion called\n")
}
shapeLayer.add(basicAnimation, forKey: "myAnimation")
CATransaction.commit()
}
fileprivate func removeAnimation() {
shapeLayer.removeAnimation(forKey: "myAnimation")
}
fileprivate func pauseShapeLayerAnimation() {
let pausedTime = shapeLayer.convertTime(CACurrentMediaTime(), from: nil)
shapeLayer.speed = 0.0
shapeLayer.timeOffset = pausedTime
print("animation has paused/stopped\n")
}
//MARK:- Anchors
fileprivate func setAnchors() {
view.addSubview(box)
view.addSubview(roundButton)
view.addSubview(timerLabel)
box.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 3).isActive = true
box.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 3).isActive = true
box.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -3).isActive = true
box.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -3).isActive = true
roundButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
roundButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
roundButton.widthAnchor.constraint(equalToConstant: 75).isActive = true
roundButton.heightAnchor.constraint(equalToConstant: 75).isActive = true
timerLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
timerLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
timerLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
}
}
//MARK:- CAAnimationDelegate
extension ViewController: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
print("***** animation done *****\n")
}
}
//MARK:- Timer Methods
extension ViewController {
fileprivate func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] _ in
self?.timerIsRunning()
})
}
@objc fileprivate func timerIsRunning() {
updateTimerLabel()
if !isBasicAnimationAnimating {
isBasicAnimationAnimating = true
addProgressAnimation()
}
milliseconds -= 1
if milliseconds < 0 {
milliseconds = 9
if seconds != 0 {
seconds -= 1
} else {
invalidateTimer()
print("timer done\n")
}
}
if milliseconds == 0 {
milliseconds = 0
}
}
fileprivate func updateTimerLabel() {
let millisecStr = "\(milliseconds)"
let secondsStr = seconds > 9 ? "\(seconds)" : "0\(seconds)"
timerLabel.text = "\(secondsStr).\(millisecStr)"
}
fileprivate func resetTimerSecsAndLabel() {
milliseconds = 0
seconds = maxTimeInSecs
timerLabel.text = initialStrForTimerLabel
}
fileprivate func invalidateTimer() {
if isBasicAnimationAnimating {
isBasicAnimationAnimating = false
if seconds != 0 {
pauseShapeLayerAnimation()
}
}
timer?.invalidate()
}
}
//MARK:- Gestures
extension ViewController {
fileprivate func setGestures() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGesture))
roundButton.addGestureRecognizer(tapRecognizer)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressGesture))
roundButton.addGestureRecognizer(longPressRecognizer)
}
@objc private func tapGesture(recognizer: UITapGestureRecognizer) {
print("tap\n")
}
@objc private func longPressGesture(recognizer: UILongPressGestureRecognizer) {
switch recognizer.state {
case .began:
resetTimerSecsAndLabel()
startTimer()
print("long gesture began\n")
case .ended, .cancelled:
invalidateTimer()
print("long gesture ended or cancelled\n")
case .failed:
print("long gesture failed\n")
default:
break
}
}
}
最佳答案
我认为动画提前完成是三个因素造成的错觉:
CAMediaTimingFunctionName.easeInEaseOut
,这意味着绘图开始缓慢并且结束缓慢,因此很难判断绘图的真正结束。0.1
,因为当计时器首次更新时 0.1
已经过去。当我将计时函数更改为 CAMediaTimingFunctionName.linear
并修复计时器时,它似乎总是在绘图完成时达到 0
。
关于ios - CABasicAnimation 比它设置的时间更快地到达它的端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62711675/
我正在尝试制作一个程序,显示飞机到达和起飞的时间表,然后要求用户在 C 中输入时间。然后程序将找到最接近输入时间的到达时间用户。问题是它没有按预期工作,并且给我一个错误的到达时间,甚至不接近输入的时间
我有一个不断填充新信息行的 Excel 表,其中一列与联系客户的日期(有时为空 - 无需输入日期)相关,如果在 10 内没有收到回复从那以后的几天,我们必须发送提醒,如果过了 17 天,我们必须取消订
实际到达很简单,标签进入接收器天线范围,但是偏离是造成问题的原因。 首先,我们了解一些有关设置的信息。 标签: 它们以433Mhz的速度工作,每1.5秒钟发送一次“心跳”,移动时进入传输突发模式,这种
我构建了这段代码来从 URL 获取 XML我使用了 AsyncTask,当到达 getInputStream() 点时,半身应用程序仍然崩溃 重点是我想从 url 获取 XML 作为字符串。 我尝试不
所以我有一个 TDBGrid,我的目的是搜索 DBGrid 的 Fieldname 并将其与我的编辑的 Text 属性进行比较,如果它们相等,则 我想将找到匹配项的整列写入列表框。 通过带有 fiel
我会写得非常简单,因为实际的修复并不比我不理解的实际设计重要。似乎一旦我的 @RequestBody 命中 @Controller,有关 subtype 的信息就会丢失。 假设我们有: class A
所以我正在做这个简单的动态编程问题,关于达到 n一次只能走 1 或 2 步。我知道答案基本上是一个斐波那契序列,答案是:达到n-2的步骤数+ 到达 n-1 的步数. T(n) = T(n-1) +
(function start (){ $('.bar').each(function(i){ var $bar = $(this); $(this).append('')
我有一个程序,我在启动它之前要求用户输入。 public static void main(String args[]) { String database = JOptionPane.sho
就是这样,我必须在提交按钮上有一张图片,但它根本没有出现。 我希望它看起来像这样: 现在看到我的是这样的,我不明白为什么它没有出现在页面上。 HTML CSS #sognu { bac
click here 点击后重定向至 xyz.com/#contact, 现在我想获得div #abc的顶部位置 //set the value as a variable, and remove t
here is a fiddle to know where I am starting from 我要解决的问题涉及对单个 html 文件的内容进行“分页”,以一种将它们一次锁定在一个部分中的方式。
是否可以在传递页面部分时运行 javascript 函数?我想要实现的是类似于 Twitter Bootstrap 的 scrollspy。 最佳答案 您可以使用 waypoints 插件: http
我有一个可以动态调整其大小的 iframe。我通过父页面上的发布消息和监听器解决了这个问题,因此每次 iframe 的内容发生变化时,iframe 的大小也会发生变化,并且永远不会有滚动条。 在 if
我试图让我的导航栏在到达我在网站下方设置的 anchor 时变得透明。 这是我的HTML Home About Logo W
我写了一个简单的程序来管理姓名列表(下面是程序的一部分)。我希望函数“choice()”结束并返回到 main()——从而结束程序——当用户对变量“option”的输入为 4 时。然而,choice(
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
代码片段在 while 循环后有一个 EOF,之后必须再次重新打开文件 - fopen 被重用。我的问题是是否有办法避免这种笨拙的 fopen 双重使用或以某种方式不使用 EOF? if (!(f=f
从这个页面: http://www.beta.inegi.org.mx/app/buscador/default.html?q=e15a61a 我正在尝试检索此网址: http://www.beta.
我使用维基百科的 API 来获取有关页面的信息。API 给我这样的 JSON: "query":{ "pages":{ "188791":{ "pageid":18879
我是一名优秀的程序员,十分优秀!