Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/105.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 设置自定义UITableViewCell动画时的计时问题_Ios_Swift_Uitableview_Uiviewanimation - Fatal编程技术网

Ios 设置自定义UITableViewCell动画时的计时问题

Ios 设置自定义UITableViewCell动画时的计时问题,ios,swift,uitableview,uiviewanimation,Ios,Swift,Uitableview,Uiviewanimation,我的应用程序架构有问题 我有一个UITableView,其中填充了自定义UITableViewCells。 当然,我使用了出列,所以只生成了8-10个单元实例 继续我的问题。。。我已经在我的应用程序中添加了一个主题功能。 当用户长时间触摸主UI时,会在应用程序范围内发布通知,通知每个viewController更新其UI 承载带有自定义单元格的tableView的viewController收到通知时,将调用tableView.reloadData 这很好,因为我已经实现了func tableV

我的应用程序架构有问题

我有一个UITableView,其中填充了自定义UITableViewCells。 当然,我使用了出列,所以只生成了8-10个单元实例

继续我的问题。。。我已经在我的应用程序中添加了一个主题功能。 当用户长时间触摸主UI时,会在应用程序范围内发布通知,通知每个viewController更新其UI

承载带有自定义单元格的tableView的viewController收到通知时,将调用tableView.reloadData

这很好,因为我已经实现了func tableView utableview:UITableView,willDisplay cell:UITableViewCell,forRowAt indexPath:indexPath

在willDisplay中,我调用自定义tableViewCell上的一个方法,该方法使用UIViewAnimation对单元格进行适当的颜色更改

看起来是这样的:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let newsFeedItemCell = cell as? NewsFeedItemCell {
        if (self.nightModeEnabled) {
            newsFeedItemCell.transitionToNightMode()
        } else {
            newsFeedItemCell.transitionFromNightMode()
        }
    }
}
func transitionToNightMode() {
        UIView.animate(withDuration: 1, animations: {
            self.backgroundColor = UIColor.black
            self.titleTextView.backgroundColor = UIColor.black
            self.titleTextView.textColor = UIColor.white
        })
}

func transitionFromNightMode() {
    UIView.animate(withDuration: 1, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
}
fileprivate var transitionAnimator: UIViewPropertyAnimator?

fileprivate func finishAnimatorAnimation() {
    // if there is a transitionAnimator, immediately finishes it
    if let animator = transitionAnimator {
        animator.stopAnimation(false)
        animator.finishAnimation(at: .end)
        transitionAnimator = nil
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    finishAnimatorAnimation()
}

func transitionToNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.black
        self.titleTextView.backgroundColor = UIColor.black
        self.titleTextView.textColor = UIColor.white
    })
    transitionAnimator?.startAnimation()
}

func transitionFromNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
    transitionAnimator?.startAnimation()
}
在自定义单元实现中,这些方法如下所示:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let newsFeedItemCell = cell as? NewsFeedItemCell {
        if (self.nightModeEnabled) {
            newsFeedItemCell.transitionToNightMode()
        } else {
            newsFeedItemCell.transitionFromNightMode()
        }
    }
}
func transitionToNightMode() {
        UIView.animate(withDuration: 1, animations: {
            self.backgroundColor = UIColor.black
            self.titleTextView.backgroundColor = UIColor.black
            self.titleTextView.textColor = UIColor.white
        })
}

func transitionFromNightMode() {
    UIView.animate(withDuration: 1, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
}
fileprivate var transitionAnimator: UIViewPropertyAnimator?

fileprivate func finishAnimatorAnimation() {
    // if there is a transitionAnimator, immediately finishes it
    if let animator = transitionAnimator {
        animator.stopAnimation(false)
        animator.finishAnimation(at: .end)
        transitionAnimator = nil
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    finishAnimatorAnimation()
}

func transitionToNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.black
        self.titleTextView.backgroundColor = UIColor.black
        self.titleTextView.textColor = UIColor.white
    })
    transitionAnimator?.startAnimation()
}

func transitionFromNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
    transitionAnimator?.startAnimation()
}
这个很好用。。。问题是:

滚动tableView时,任何不在屏幕上的单元格在滚动到屏幕上时都会调用颜色更新/动画代码,这会导致不和谐的用户体验

我当然理解为什么会发生这种情况,因为willDisplay只被称为cells display

我想不出一个优雅的方法来避免这种情况

我很高兴屏幕上的细胞正在为用户体验制作动画,然而,对于屏幕外的细胞,我宁愿他们跳过动画

可能的解决方案,尽管不美观:

保留对cellForRow创建的8-10个单元格的引用,并检查它们是否在屏幕外,是否立即设置了状态

但是,我不喜欢保留每个单元格的引用


有什么想法吗?

我想试试下面的方法

在transitionTo/FromNightMode中,我不使用UIView.animate,而是创建一个UIViewPropertyAnimator对象,该对象将执行相同的动画。我将保留对该对象的引用,然后准备重用,如果动画仍在运行,我只需完成该动画并重置状态。比如说:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let newsFeedItemCell = cell as? NewsFeedItemCell {
        if (self.nightModeEnabled) {
            newsFeedItemCell.transitionToNightMode()
        } else {
            newsFeedItemCell.transitionFromNightMode()
        }
    }
}
func transitionToNightMode() {
        UIView.animate(withDuration: 1, animations: {
            self.backgroundColor = UIColor.black
            self.titleTextView.backgroundColor = UIColor.black
            self.titleTextView.textColor = UIColor.white
        })
}

func transitionFromNightMode() {
    UIView.animate(withDuration: 1, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
}
fileprivate var transitionAnimator: UIViewPropertyAnimator?

fileprivate func finishAnimatorAnimation() {
    // if there is a transitionAnimator, immediately finishes it
    if let animator = transitionAnimator {
        animator.stopAnimation(false)
        animator.finishAnimation(at: .end)
        transitionAnimator = nil
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    finishAnimatorAnimation()
}

func transitionToNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.black
        self.titleTextView.backgroundColor = UIColor.black
        self.titleTextView.textColor = UIColor.white
    })
    transitionAnimator?.startAnimation()
}

func transitionFromNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
    transitionAnimator?.startAnimation()
}

我会尝试以下方法

在transitionTo/FromNightMode中,我不使用UIView.animate,而是创建一个UIViewPropertyAnimator对象,该对象将执行相同的动画。我将保留对该对象的引用,然后准备重用,如果动画仍在运行,我只需完成该动画并重置状态。比如说:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let newsFeedItemCell = cell as? NewsFeedItemCell {
        if (self.nightModeEnabled) {
            newsFeedItemCell.transitionToNightMode()
        } else {
            newsFeedItemCell.transitionFromNightMode()
        }
    }
}
func transitionToNightMode() {
        UIView.animate(withDuration: 1, animations: {
            self.backgroundColor = UIColor.black
            self.titleTextView.backgroundColor = UIColor.black
            self.titleTextView.textColor = UIColor.white
        })
}

func transitionFromNightMode() {
    UIView.animate(withDuration: 1, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
}
fileprivate var transitionAnimator: UIViewPropertyAnimator?

fileprivate func finishAnimatorAnimation() {
    // if there is a transitionAnimator, immediately finishes it
    if let animator = transitionAnimator {
        animator.stopAnimation(false)
        animator.finishAnimation(at: .end)
        transitionAnimator = nil
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    finishAnimatorAnimation()
}

func transitionToNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.black
        self.titleTextView.backgroundColor = UIColor.black
        self.titleTextView.textColor = UIColor.white
    })
    transitionAnimator?.startAnimation()
}

func transitionFromNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
    transitionAnimator?.startAnimation()
}
我不会使用重载数据来设置动画,因为tableview的数据模型实际上没有改变

相反,我会给UITableView一个函数,如下所示:

class myClass : UITableViewController {
    ....

    func transitionToNightMode() {
            for visible in visibleCells {
            UIView.animate(withDuration: 1, animations: {
                visible.backgroundColor = UIColor.black
                visible.titleTextView.backgroundColor = UIColor.black
                visible.titleTextView.textColor = UIColor.white
            })
            }
    }
}
然后在willDisplay或cellForItemAt中,设置正确的外观而不设置动画。

我不会使用重载数据来设置动画,因为tableview的数据模型实际上没有改变

相反,我会给UITableView一个函数,如下所示:

class myClass : UITableViewController {
    ....

    func transitionToNightMode() {
            for visible in visibleCells {
            UIView.animate(withDuration: 1, animations: {
                visible.backgroundColor = UIColor.black
                visible.titleTextView.backgroundColor = UIColor.black
                visible.titleTextView.textColor = UIColor.white
            })
            }
    }
}

然后在您的willDisplay或cellForItemAt中,设置正确的外观而不使用动画。

令人愉快的解决方案。打电话反对可见细胞可以吗?只有在更改数据时才能调用reload,对吗?@Woodstock,谢谢!是的,这是对可见单元格的调用。与任何其他UIView一样,可见单元格也是层次结构的一部分。有时我会变得懒惰,在我真的不需要的时候使用重载,但它通常用于数据模型中的更改,而不仅仅是用于视觉外观。这是一个令人愉快的解决方案。打电话反对可见细胞可以吗?只有在更改数据时才能调用reload,对吗?@Woodstock,谢谢!是的,这是对可见单元格的调用。与任何其他UIView一样,可见单元格也是层次结构的一部分。有时我会变得懒惰,在我真的不需要的时候使用重载,但它通常用于数据模型中的更改,而不仅仅是用于视觉外观。