簡體   English   中英

iOS TableView ScrollToRow 空屏問題

[英]iOS TableView ScrollToRow Empty Screen Problem

我正在嘗試使用 scrollToRow 但是當調用此方法時,tableview 有時不顯示任何數據。 當我檢查 UI 檢查器時,我可以看到表格單元格,但在屏幕上看不到。

我試過 DispactQueue 沒有解決這個問題

var forIndex = 0
    for item in filteredData {
        if let firstCharacter = item.Name?.prefix(1), firstCharacter == char {
           let indexpath = IndexPath(row: forIndex, section: 0)
           self.tableView.reloadRows(at: [indexpath], with: UITableView.RowAnimation.top)
           DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute: { [weak self] in
           self?.tableView.scrollToRow(at: indexpath, at: UITableView.ScrollPosition.top, animated: true)
                    })
                    break
                }
                forIndex += 1
                }

char 是列表的元素,如 a、b、c、d... FilteredData 是 tableview 元素的列表

調試 scrollToRow 方法是否標記斷點時它正在工作

可能是reloadRows (at:) animation 仍在進行中,當你踢下一個導致這種奇怪的行為時。

使用斷點, reloadRows (at:)有機會完成並continuing scrollToRow之后開始。

假設您的數據源沒有問題,如果這對您的情況有幫助,請嘗試以下操作之一:

1.改變

tableView.reloadRows(at: [indexpath], with: .top)

tableView.reloadRows(at: [indexpath], with: .none)以便 UITableView 應用默認值 animation

或者

2.在開始下一個animation之前增加你的延遲

或者

3.在沒有animation的情況下執行重新加載

UIView.performWithoutAnimation { [weak self] in
    self?.tableView.reloadRows(at: [indexpath], with: .none)
}


tableView.scrollToRow(at: indexpath,
                            at: UITableView.ScrollPosition.top,
                            animated: true)

或者

4. 使用beginUpdatesendUpdates這在對表視圖執行批操作時很有用

tableView.beginUpdates()

tableView.reloadRows(at: [indexpath], with: .top)

tableView.scrollToRow(at: indexpath,
                            at: UITableView.ScrollPosition.top,
                            animated: true)

tableView.endUpdates()

這些是否會給您帶來更好的結果?

更新

更多地查看reloadRows(at indexPaths:文檔,這里有一些對我來說很突出的行

如果您想提醒用戶單元格的值正在更改,請調用此方法。 但是,如果通知用戶並不重要——也就是說,您只想更改單元格顯示的值——您可以獲取特定行的單元格並設置其新值。

因此,似乎在某些情況下可能不需要 animation,因為單元格可能不在屏幕上或不需要,因此更改數據的最簡單方法是在索引路徑處獲取單元格並在沒有此 function 的情況下更改數據。

由於您在循環中運行它,您很可能在前一個 indexPath 的scrollToRow完成之前啟動下一個 indexPath 的reloadRows ,這可能會導致一些異常行為。

由於 UITableView 沒有自己的完成處理程序,我們可以嘗試使用帶有遞歸的 CoreAnimation,這可以是選項 5。

這是我准備的小例子。 我的樣本是這樣的:

  1. 我有 15 行是灰色的
  2. 我決定要更改 4 行的顏色
  3. 我將 4 行的索引存儲在一個隊列中
  4. 我將使用tableView.reloadRows(at:
  5. 更改顏色后,我想使用tableView.scrollToRow(at:

這是我如何做到的

首先,我擴展 UITableView 以使用 CoreAnimation 塊來執行reloadRowsscrollToRow

extension UITableView
{
    func reloadRows(at indexPaths: [IndexPath],
                    with animation: UITableView.RowAnimation,
                    completion: (() -> Void)?)
    {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        reloadRows(at: indexPaths, with: animation)
        CATransaction.commit()
    }
    
    func scrollToRow(at indexPath: IndexPath,
                     at scrollPosition: UITableView.ScrollPosition,
                     animated: Bool,
                     completion: (() -> Void)?)
    {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        CATransaction.setAnimationDuration(2) // set what you want
        scrollToRow(at: indexPath, at: scrollPosition, animated: animated)
        CATransaction.commit()
    }
}

以下是我如何在我的視圖 controller 設置中使用此擴展

class TableViewAnimation: UITableViewController
{
    let numberOfRows = 15
    
    // Change the color of these rows in tableview
    var colorChangeArray: [Int] = []
    
    // Copy of colorChangeArray used in recursion
    var colorChangeQueue: [Int] = []
    
    // Change the color of row to this
    private let colorToChange = UIColor.systemBlue
    
    // Normal cell color
    private let colorNormal = UIColor.gray
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        setUpNavigationBar()
        setUpTableView()
    }
    
    private func setUpNavigationBar()
    {
        title = "Table View Animate"
        
        let barButton = UIBarButtonItem(title: "Animate",
                                        style: .plain,
                                        target: self,
                                        action: #selector(didTapAnimateButton))
        
        navigationItem.rightBarButtonItem = barButton
    }
    
    private func setUpTableView()
    {
        tableView.register(CustomCell.self,
                           forCellReuseIdentifier: CustomCell.identifier)
    }
    
    @objc
    func didTapAnimateButton()
    {
        // Queue all the rows that should change
        // We will dequeue these in the animation function
        // and the recursive function stops when the queue
        // is empty
        colorChangeQueue = [1, 3, 6, 12]
        
        resumeAnimation()
    }
    
    // Recursion function rather than loops using our
    // custom functions from extension
    private func resumeAnimation()
    {
        if !colorChangeQueue.isEmpty
        {
            let rowToChange = colorChangeQueue.removeFirst()
            
            print("starting \(rowToChange) animation")
            
            let indexPath = IndexPath(row: rowToChange,
                                      section: 0)
            
            colorChangeArray.append(rowToChange)
            
            tableView.reloadRows(at: [indexPath],
                                 with: .top) { [weak self] in
                
                self?.tableView.scrollToRow(at: indexPath,
                                            at: .top,
                                            animated: true,
                                            completion: {
                    
                    // recursively call the function again with a small delay
                    DispatchQueue.main.asyncAfter(deadline: .now() + 1)
                    {
                        print("complete \(rowToChange) animation")
                        self?.resumeAnimation()
                    }
                })
            }
        }
    }
}

最后,這是數據源和委托,但這里沒有發生任何獨特的事情,只是為了完整性而添加它

extension TableViewAnimation
{
    override func tableView(_ tableView: UITableView,
                            numberOfRowsInSection section: Int) -> Int
    {
        return numberOfRows
    }
    
    override func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell
            = tableView.dequeueReusableCell(withIdentifier: CustomCell.identifier) as! CustomCell
        
        if colorChangeArray.contains(indexPath.row)
        {
            cell.mainView.backgroundColor = colorToChange
        }
        else
        {
            cell.mainView.backgroundColor = colorNormal
        }
        
        cell.textLabel?.textAlignment = .center
        cell.textLabel?.text = "Row \(indexPath.row)"
        
        return cell
    }
    
    override func tableView(_ tableView: UITableView,
                   heightForRowAt indexPath: IndexPath) -> CGFloat
    {
        return 150
    }
}

現在似乎每一行的動畫都正確排序了:

UITableView 動畫完成滾動以重新加載行 iOS Swift

而且,如果您在控制台中看到打印,它是按順序排列的,而循環方法不會發生:

starting 1 animation
complete 1 animation
starting 3 animation
complete 3 animation
starting 6 animation
complete 6 animation
starting 12 animation
complete 12 animation

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM