我面臨的問題本身很容易描述。
我的應用程式中有一個表格視圖,其中影片是異步啟動的。對于一次索引路徑,影片只發生一次。如果我將單元格滾動到可見區域之外,我認為該索引路徑的影片已完成。即下次索引路徑回到可見區域時,我將其設定為沒有影片的最終值。如果我不滾動,影片會按預期作業。
但是,當我滾動表格視圖時,因為單元格被重用,并且打算在當前不可見的單元格上執行的影片仍在現在可見的單元格上執行。我已經整理了一個示例代碼來描述我的問題。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath)
cell.textLabel?.layer.opacity = 1
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 0
} completion: { [weak cell] _ in
cell?.textLabel?.layer.opacity = 0
cell?.textLabel?.text = "\(indexPath.row)"
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 1
} completion: { [weak cell] _ in
cell?.textLabel?.layer.opacity = 1
cell?.textLabel?.text = "\(indexPath.row)"
}
}
animated[indexPath.row].toggle()
return cell
}
}
為了在單元格超出表格視圖的范圍時停止影片,我嘗試在單元格中保存影片的參考,并在單元格出列后立即洗掉。但這對我的情況沒有幫助。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
var animated: [Bool] = Array(repeating: false, count: 100)
}
class TestCell: UITableViewCell {
var animations: [UIViewPropertyAnimator] = []
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestCell
if !animated[indexPath.row] {
//Stop animations if any
cell.animations.forEach { animator in
animator.stopAnimation(true)
}
cell.animations.removeAll()
//
let animator = UIViewPropertyAnimator(duration: 5, curve: .easeIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 0
}
animator.addCompletion { [weak cell] completed in
cell?.textLabel?.layer.opacity = 0
cell?.textLabel?.text = "\(indexPath.row)"
if completed == .end {
let animator1 = UIViewPropertyAnimator(duration: 5, curve: .easeIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 1
}
animator1.addCompletion { [weak cell] _ in
cell?.textLabel?.layer.opacity = 1
cell?.textLabel?.text = "\(indexPath.row)"
}
animator1.startAnimation(afterDelay: 0)
cell?.animations.append(animator1)
}
}
animator.startAnimation(afterDelay: 0)
cell.animations.append(animator)
animated[indexPath.row].toggle()
} else {
cell.textLabel?.layer.opacity = 1
cell.textLabel?.text = "\(indexPath.row)"
}
return cell
}
}
我在 SO 上找不到任何類似的東西。任何幫助表示贊賞。
uj5u.com熱心網友回復:
在單元類中設定/停止影片:
class TestCell: UITableViewCell {
var animation : UIViewPropertyAnimator?
// call this in cellForRow in tableView controller
func startAnimation() {
… create animation and save it in self.animation
}
func stopAnimation () {
… stop animation
}
override func prepareForReuse() {
super.prepareForReuse()
StopAnimation();
}
}
uj5u.com熱心網友回復:
這是一個有點奇怪的影片序列,但我猜這更多是為了測驗/弄清楚它以供您實際使用。
這可能會幫助...
prepareForReuse()在您的單元格中實作以停止和洗掉任何正在執行的影片,并將標簽的不透明度設定為1.0。
在 中cellForRowAt,將animated陣列中的插槽設定為false而不是切換它,因為您只希望影片在第一次出現行時運行。
同樣在 中cellForRowAt,請確保將單元格的標簽“重置”為其初始值。
試試這個,看看它是否能讓你更接近你的目標:
class TestCell: UITableViewCell {
var animations: [UIViewPropertyAnimator] = []
override func prepareForReuse() {
super.prepareForReuse()
animations.forEach { animator in
animator.stopAnimation(true)
}
animations.removeAll()
textLabel?.layer.opacity = 1.0
}
}
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
var animated: [Bool] = Array(repeating: false, count: 100)
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestCell
if !animated[indexPath.row] {
animated[indexPath.row] = true
// cells are reused, so "reset" the initial label text
cell.textLabel?.text = "Needs to animate..."
//
let animator = UIViewPropertyAnimator(duration: 5, curve: .easeIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 0
}
animator.addCompletion { [weak cell] completed in
cell?.textLabel?.layer.opacity = 0
cell?.textLabel?.text = "\(indexPath.row)"
if completed == .end {
let animator1 = UIViewPropertyAnimator(duration: 5, curve: .easeIn) { [weak cell] in
cell?.textLabel?.layer.opacity = 1
}
animator1.addCompletion { [weak cell] _ in
cell?.textLabel?.layer.opacity = 1
cell?.textLabel?.text = "\(indexPath.row)"
}
animator1.startAnimation(afterDelay: 0)
cell?.animations.append(animator1)
}
}
animator.startAnimation(afterDelay: 0)
cell.animations.append(animator)
} else {
cell.textLabel?.layer.opacity = 1
cell.textLabel?.text = "\(indexPath.row)"
}
return cell
}
}
編輯
注意影片完成塊...
首先,您用作completed完成塊引數 - 您可能會誤導自己,因為它不是 Bool 值......它是一個UIViewAnimatingPosition值。
來自 Apple 的檔案:
影片的結束位置。使用此值來確定影片是在開頭、結尾還是中間的某個位置停止。
完成塊在影片正常完成后執行。如果您呼叫 stopAnimation(_:) 方法,并且您為該方法的引數指定 true ,則不會呼叫完成塊。如果您為該引數指定 false,則影片制作器會在您呼叫其 finishAnimation(at:) 方法后正常執行完成塊。
所以,如果你的
animator.stopAnimation(true)
在第一個影片完成之前呼叫,它的完成塊不會被呼叫。
如果在第一個影片完成后,但在第二個影片完成之前呼叫它,則不會呼叫第二個影片的完成塊。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/369657.html
上一篇:如何在PDFView(swiftPDFKit)中注釋圓形、縱橫填充影像
下一篇:如何從串列中的串列中洗掉括號?
