【问题标题】:Mac Catalyst: tableView allowmultipleselection not workingMac Catalyst:tableView 允许多重选择不起作用
【发布时间】:2020-07-06 11:00:51
【问题描述】:

我有一个允许多选的表格视图。我在 viewDidLoad 中将allowMultipleSelection 和allowsMultipleSelectionDuringEditing 都设置为true,这在iOS 和iPadOS 上都能完美运行。我决定今天试用 Catalyst,该应用程序看起来不错,只是我无法在此视图中选择多行。有任何想法吗?这是下面的代码。非常感谢。

//允许多选

override func viewDidLoad() 
{
    super.viewDidLoad()

    self.tableView.allowsMultipleSelection = true
    self.tableView.allowsMultipleSelectionDuringEditing = true
.....
}

//限制选择为7行

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    if let selectedItems = tableView.indexPathsForSelectedRows {

        if selectedItems.count > 6 {
            return nil
        }
    }
    return indexPath
}

@IBAction func doneButtonTapped(_ sender: UIBarButtonItem) {

...

    let selectedIndexPaths = tableView.indexPathsForSelectedRows
    if !selectedIndexPaths!.isEmpty {
        for index in selectedIndexPaths! {
            let selectedProcedure = fetchedResultsController?.object(at: index) as! Item
...

Rest of code to perform the required task
}

【问题讨论】:

    标签: swift mac-catalyst


    【解决方案1】:

    macOS Catalyst 上的多项选择与在 iOS 和 iPadOS 上的工作方式不同,这似乎是一个错误,或者是对预期行为的不幸选择。

    在 macOS Catalyst 上,如果您通过将 tableView.allowsMultipleSelectionDuringEditing 设置为 true 来启用编辑模式下的多选,则一次只能通过指针单击直接选择一行。但是,通过选择第一行然后在选择第二行时按住 SHIFT 来启用连续行的多选,通过选择第一行然后在选择其他行时按住 COMMAND 来启用非连续行的多选。这是类似于 Mac 的行为,因为它是多选通常在 macOS 上的工作方式。因此,这可能是预期的行为。但如果是这样的话,这是难以发现的行为,而不是 iOS/iPadOS 用户可能期望的,并且与 iOS 和 iPadOS 上的工作方式不同。它会导致其他问题 - 例如,在代码中,我有一个“全选”功能,能够从 iOS/iPadOS 上的代码中选择所有行,而此代码在 macOS Catalyst 上不起作用。

    我对此提交了反馈。 GitHub 上有一个简单的项目WB2ISS/MultipleSelection 可以演示该问题。

    【讨论】:

    • 感谢您提供详细而清晰的答案,您的项目清楚地展示了这种行为。我也不同意这种方法,因为-正如您所说-很难发现,并且用户在他们的设备上的行为应该是一致的。我想唯一的出路是向苹果提交反馈并希望最好!再次感谢。
    • 看起来 Apple 故意选择这种行为以与 macOS 行为保持一致,但是,在撰写本文时绝对没有关于它的文档。我们的应用看起来不像 Mac 应用,它看起来像 iPad 应用(因为 Catalyst)。我的观点是,用户将与应用程序进行交互,就好像它是 iPad 应用程序而不是 Mac 应用程序一样;因此,不会想到 command + click 来执行多选。
    • 嗨 :) 在我的应用程序中,我不需要进入编辑模式,所以我只有 tableView.allowsMultipleSelection = true。这在 iOS 中可以很好地选择一个或多个单元格。但是在不能使用 Shift/Command+click 的 Catalyst 上……有人有幸在这种模式下选择多个单元格吗?谢谢! :)
    【解决方案2】:

    虽然这里所说的一切都是真的,但有一种“简单”的方法可以破解这种行为。使用下面的代码,您将在 Mac 上获得与在 iOS/iPadOS 上相同的行为

    #if targetEnvironment(macCatalyst)
    func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
            tableView.deselectRow(at: indexPath, animated: false)
            return nil
        }
        return indexPath
    }
    
    func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
        if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
            return nil
        }
        return indexPath
    }
    
    func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
        // the mac sets isHighlighted of each other cell to false before selecting them again which leads to a flickering of the selection. Therefore go through the selected cells and highlight them here manually
        tableView.indexPathsForSelectedRows?.forEach { tableView.cellForRow(at: $0)?.isHighlighted = true }
        return true
    }
    #endif
    

    【讨论】:

    • 感谢分享这个解决方法;对我来说,每个选定的单元格"blinks" 每次选择/取消选择一个新单元格时;这也发生在你身上吗?您找到解决方法了吗?
    • 我也找到了解决方法并相应地编辑了答案。你必须覆盖shouldHighlightRowAt
    • 这是一个很好的解决方法。编辑结束时,我发现有必要删除为减轻闪光/闪烁而添加的高光。此外,当从代码中进行选择时,比如实现全选函数,问题仍然存在,因为.selectRow(at:animated:scrollPosition:) 没有调用willSelectRowAtwillDeselectRowAt 委托方法。尽管整体多选行为是预期的,但.selectRow(at:animated:scrollPosition:) 的当前行为显然是一个错误。希望它会在 macOS 11 中得到修复。
    【解决方案3】:

    以下是@ph1lb4 提供的解决方案,打包为独立的class。重要的是,这个版本在选择行时会调用didSelectRowAt,这意味着依赖于didSelectRowAt 的子类不会中断。

    import UIKit
    
    // WORKAROUND:
    // As of macOS 10.15 Catalina, multi-row selection in Catalyst apps is not
    // intuitive. The user is expected to use the shift key to select multiple
    // rows. See https://stackoverflow.com/q/60856636/1306956 for more details.
    open class CatalystWorkaroundTableViewController: UITableViewController {
        #if targetEnvironment(macCatalyst)
        override open func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
            if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
                tableView.deselectRow(at: indexPath, animated: false)
                self.tableView(tableView, didSelectRowAt: indexPath)
                return nil
            } else {
                return indexPath
            }
        }
    
        override open func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
            if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
                return nil
            } else {
                return indexPath
            }
        }
    
        // WORKAROUND:
        // Catalyst de-highlights cells beofre selecting them again which results in flickering.
        override open func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
            for indexPath in tableView.indexPathsForSelectedRows ?? [] {
                tableView.cellForRow(at: indexPath)?.isHighlighted = true
            }
            return true
        }
        #endif
    }
    

    【讨论】:

      【解决方案4】:

      好消息!在 macOS Big Sur UITableView tableView.allowsMultipleSelection = true 就像在 iOS 中一样工作!快乐的时光!您还可以通过编程方式选择多个单元格!

      【讨论】:

      • 我正在使用 Big Sur,截至 2021 年 9 月,我的 Mac Catalyst 应用程序中仍然存在 OP 概述的行为。
      • @lukemmtt 您是否使用 Command 键来选择更多?还有范围的Shift键?我这里没有我的应用,所以我现在不能自己尝试,抱歉。
      • command 键和 shift 键工作得非常好——但我和大多数用户都不会想到为像我这样使用 iPad 习语的 Mac Catalyst 应用程序这样做(即不是“为 mac 优化” )。这里的其他答案一致认为,这种行为要么是错误,要么是 Apple 的错误决定。在将我的 iPad 应用程序移植到 Mac Catalyst 时,我希望所有用户交互都保持不变,因为它们看起来几乎相同。最终,我在上面实现了 Rudolf Adamkovič 的基于类的解决方案,它在恢复预期的用户体验方面很有魅力——点击选择/取消选择。
      • 好的,我明白了。我的评论是它完全被破坏了,但后来它开始在大苏尔工作。我认为它是否符合 iPad 体验是另一个讨论:)
      【解决方案5】:

      下面是objective-c中写的解决方案。

      谢谢。 @ph1lb4

      #if TARGET_OS_MACCATALYST
          
      - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      
          NSArray<NSIndexPath *> * selectedRows = [tableView indexPathsForSelectedRows];
          if ([selectedRows containsObject:indexPath]) {
              [tableView deselectRowAtIndexPath:indexPath animated:false];
              
              return nil;
          }
      
          return indexPath;
      }
      
      - (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
          NSArray<NSIndexPath *> * selectedRows = [tableView indexPathsForSelectedRows];
          if ([selectedRows containsObject:indexPath]) {
              return nil;
          }
          return indexPath;
      }
      
      - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
          NSArray<NSIndexPath *> * selectedRows = [tableView indexPathsForSelectedRows];
          for(NSIndexPath *index in selectedRows){
              [[tableView cellForRowAtIndexPath:index] setHighlighted:YES];
          }
          
          return YES;
      }
      
      #else
      
      - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
          
          return indexPath;
          
      }
      
      - (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
          return indexPath;
      }
      
      
      #endif
      

      【讨论】:

        猜你喜欢
        • 2011-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-14
        • 2015-01-10
        • 1970-01-01
        • 1970-01-01
        • 2012-12-18
        相关资源
        最近更新 更多