You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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、且渐变平滑的效果,按以下步骤修改:

  1. 把所有辅助方法移到和viewDidLoad、panPerformed同级的类作用域下,不要嵌套在viewDidLoad里
  2. 修复addOrSubtract()的返回值,返回计算好的result而不是空的Int()
  3. 新增移动距离计数器,累计手势移动的距离,每累计到指定阈值才触发一次颜色更新,直接把触发频率降到原来的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:36:22