UIPanGestureRecognizer拖动时背景色变化过快及变黑问题排查
问题描述
我实现了panPerformed()和randomColors()方法,当手指在屏幕上拖动时,视图的颜色变化速度过快。
请问使用Pan Gesture拖动手势时,如何让背景颜色的变化速度减慢为原来的1/3?
初始实现代码:
func randomColors() -> UIColor { let r = CGFloat(arc4random_uniform(255)) / 255.0 let g = CGFloat(arc4random_uniform(255)) / 255.0 let b = CGFloat(arc4random_uniform(255)) / 255.0 return UIColor(red: r, green: g, blue: b, alpha: 1.0) } @IBAction func panPerformed(_ sender: UIPanGestureRecognizer) { if sender.state == .began || sender.state == .changed { let changeX = (self.view?.center.x)! let changeY = (self.view?.center.y)! sender.view?.center = CGPoint(x: changeX, y: changeY) sender.setTranslation(CGPoint.zero, in: self.view) self.view.backgroundColor = self.randomColors() } }
参考建议修改后新增了RGB值存储、渐进调色逻辑,修改后的代码如下:
// Add some instance variables: var r: Int = 0 var g: Int = 0 var b: Int = 0 override func viewDidLoad() { // Give your background view an initial color r = Int.random(in: 0...255) g = Int.random(in: 0...255) b = Int.random(in: 0...255) self.view.backgroundColor = currentColor() // Convert the r/g/b Int values to a UIColor func currentColor() -> UIColor { return UIColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1.0) } // Randomly change the input value by +/- 5 func addOrSubtract(from: Int) -> Int { var result = from + Int.random(in: -5...5) // Don't let the new value go < 0 or > 255 if result < 0 { result = 0 } else if result > 255 { result = 255 } return Int() } // Adjust the r, g, and b values up or down a little. func randomizeColor() { r = addOrSubtract(from: r) g = addOrSubtract(from: g) b = addOrSubtract(from: b) } @IBAction func panPerformed(_ sender: UIPanGestureRecognizer) { if sender.state == .began || sender.state == .changed { let changeX = (self.view?.center.x)! let changeY = (self.view?.center.y)! sender.view?.center = CGPoint (x: changeX, y: changeY) sender.setTranslation(CGPoint.zero, in: self.view) if changeX + changeY > 5 { randomizeColor() // self.view.backgroundColor = self.randomColours() - the previous code self.view.backgroundColor = currentColor() } } } }
实际运行时,手指拖动屏幕后视图直接变为黑色,没有颜色切换效果,问题是否出在addOrSubtract()方法的逻辑上?
问题原因
代码存在3处核心错误,直接导致运行异常:
addOrSubtract()方法返回值错误:方法末尾写的return Int()会固定返回0(Int的默认初始值为0),无论之前计算的result是什么值,调用后r/g/b三个颜色通道都会被置为0,对应颜色就是纯黑色,这是视图直接变黑的根本原因。- 函数作用域错误:
currentColor()、addOrSubtract()、randomizeColor()三个方法全部嵌套定义在viewDidLoad()内部,属于viewDidLoad的局部函数,外部的panPerformed手势回调方法无法正常访问这些函数,逻辑无法按预期执行。 - 触发逻辑错误:判断条件
changeX + changeY > 5里的changeX、changeY取的是视图静态中心点坐标,不是手势移动的增量距离,这个判断完全不生效。另外原代码中给center赋值的逻辑也是无效的——把当前center值重新赋值给center,视图根本不会跟着手指移动。
修正方案
要实现颜色变化速度减慢为原来的1/3、且渐变平滑的效果,按以下步骤修改:
- 把所有辅助方法移到和
viewDidLoad、panPerformed同级的类作用域下,不要嵌套在viewDidLoad里 - 修复
addOrSubtract()的返回值,返回计算好的result而不是空的Int() - 新增移动距离计数器,累计手势移动的距离,每累计到指定阈值才触发一次颜色更新,直接把触发频率降到原来的1/3即可
修正后的完整参考代码:
// 类的实例变量 var r: Int = 0 var g: Int = 0 var b: Int = 0 // 累计手势移动距离,用来控制变色频率 var panDistance: CGFloat = 0 // 变色触发阈值,数值越大变色越慢,设为3即可把速度降到原来的1/3 let colorChangeThreshold: CGFloat = 3 override func viewDidLoad() { super.viewDidLoad() // 初始化随机背景色 r = Int.random(in: 0...255) g = Int.random(in: 0...255) b = Int.random(in: 0...255) self.view.backgroundColor = currentColor() } // 辅助方法放在类作用域下 func currentColor() -> UIColor { return UIColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1.0) } func addOrSubtract(from: Int) -> Int { var result = from + Int.random(in: -5...5) if result < 0 { result = 0 } else if result > 255 { result = 255 } // 返回计算后的结果,不是默认0 return result } func randomizeColor() { r = addOrSubtract(from: r) g = addOrSubtract(from: g) b = addOrSubtract(from: b) } @IBAction func panPerformed(_ sender: UIPanGestureRecognizer) { // 手势开始时重置累计距离 if sender.state == .began { panDistance = 0 } if sender.state == .began || sender.state == .changed { // 获取本次手势移动的增量 let translation = sender.translation(in: self.view) // 累计移动距离 panDistance += abs(translation.x) + abs(translation.y) // 修正视图移动逻辑 if let movedView = sender.view { movedView.center = CGPoint(x: movedView.center.x + translation.x, y: movedView.center.y + translation.y) } sender.setTranslation(.zero, in: self.view) // 累计距离达到阈值才变色,直接把变色频率降到原来的1/3 if panDistance >= colorChangeThreshold { randomizeColor() self.view.backgroundColor = currentColor() // 重置累计距离 panDistance = 0 } } }
内容的提问来源于stack exchange,提问作者AntonyCatcher
相关产品推荐
相关产品推荐

