Mac Catalyst:tableView allowmultipleselection 不工作
Mac Catalyst: tableView allowmultipleselection not working
我有一个允许多个 selection 的表视图。我在 viewDidLoad 中将 allowsMultipleSelection 和 allowsMultipleSelectionDuringEditing 都设置为 true,这在 iOS 和 iPadOS 上都运行良好。我决定今天试用 Catalyst,该应用程序看起来不错,只是我不能在此视图中 select 多行。有任何想法吗?这是下面的代码。非常感谢。
//允许多个selection
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.allowsMultipleSelection = true
self.tableView.allowsMultipleSelectionDuringEditing = true
.....
}
//将 selection 限制为 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
}
Multiple selection 在 macOS Catalyst 上的工作方式与在 iOS 和 iPadOS 上的工作方式不同,这似乎是一个错误或不幸的预期行为选择。
在 macOS Catalyst 上,如果您通过将 tableView.allowsMultipleSelectionDuringEditing 设置为 true 在编辑模式下启用了多个 selection,则一次只能通过单击直接 selected与指针。但是,多个 selection 的连续行是通过 selecting 第一行然后在 selecting 第二行的同时按住 SHIFT 来启用的,并且多个 selection 的非-通过 selecting 第一行然后在 selecting 其他行的同时按住 COMMAND 来启用连续行。这是类似于 Mac 的行为,因为它是多个 selection 通常在 macOS 上工作的方式。所以这可能是有意为之的行为。但如果是这种情况,这种行为很难被发现,而不是 iOS/iPadOS 用户可能期望的,并且与 iOS 和 iPadOS 上的工作方式不同。它会导致其他问题 - 例如,在代码中我有一个 "Select All" 函数,它能够 select 来自 iOS/iPadOS 上代码的所有行,并且此代码在 macOS Catalyst 上不起作用.
我对此提交了反馈。在 WB2ISS/MultipleSelection 上的 GitHub 上有一个简单的项目演示了这个问题。
虽然这里所说的一切都是真实的,但有一种 'easy' 方法可以破解这种行为。使用下面的代码,您将在 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: [=10=])?.isHighlighted = true }
return true
}
#endif
下面是@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 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
}
好消息!在 macOS Big Sur UITableView tableView.allowsMultipleSelection = true
中就像在 iOS 中一样工作!快乐的时光!您还可以以编程方式创建 select 多个单元格!
下面是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
我遇到了同样的问题,但在 Catalyst 上使用了 UICollectionView。我无法实现相同的解决方案,因为 UICollectionView 缺少一些委托函数。我发现这个要点为我解决了。 https://gist.github.com/stefanceriu/5ff0c67e98ae44612857cd17fd4377d1
我有一个允许多个 selection 的表视图。我在 viewDidLoad 中将 allowsMultipleSelection 和 allowsMultipleSelectionDuringEditing 都设置为 true,这在 iOS 和 iPadOS 上都运行良好。我决定今天试用 Catalyst,该应用程序看起来不错,只是我不能在此视图中 select 多行。有任何想法吗?这是下面的代码。非常感谢。
//允许多个selection
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.allowsMultipleSelection = true
self.tableView.allowsMultipleSelectionDuringEditing = true
.....
}
//将 selection 限制为 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
}
Multiple selection 在 macOS Catalyst 上的工作方式与在 iOS 和 iPadOS 上的工作方式不同,这似乎是一个错误或不幸的预期行为选择。
在 macOS Catalyst 上,如果您通过将 tableView.allowsMultipleSelectionDuringEditing 设置为 true 在编辑模式下启用了多个 selection,则一次只能通过单击直接 selected与指针。但是,多个 selection 的连续行是通过 selecting 第一行然后在 selecting 第二行的同时按住 SHIFT 来启用的,并且多个 selection 的非-通过 selecting 第一行然后在 selecting 其他行的同时按住 COMMAND 来启用连续行。这是类似于 Mac 的行为,因为它是多个 selection 通常在 macOS 上工作的方式。所以这可能是有意为之的行为。但如果是这种情况,这种行为很难被发现,而不是 iOS/iPadOS 用户可能期望的,并且与 iOS 和 iPadOS 上的工作方式不同。它会导致其他问题 - 例如,在代码中我有一个 "Select All" 函数,它能够 select 来自 iOS/iPadOS 上代码的所有行,并且此代码在 macOS Catalyst 上不起作用.
我对此提交了反馈。在 WB2ISS/MultipleSelection 上的 GitHub 上有一个简单的项目演示了这个问题。
虽然这里所说的一切都是真实的,但有一种 'easy' 方法可以破解这种行为。使用下面的代码,您将在 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: [=10=])?.isHighlighted = true }
return true
}
#endif
下面是@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 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
}
好消息!在 macOS Big Sur UITableView tableView.allowsMultipleSelection = true
中就像在 iOS 中一样工作!快乐的时光!您还可以以编程方式创建 select 多个单元格!
下面是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
我遇到了同样的问题,但在 Catalyst 上使用了 UICollectionView。我无法实现相同的解决方案,因为 UICollectionView 缺少一些委托函数。我发现这个要点为我解决了。 https://gist.github.com/stefanceriu/5ff0c67e98ae44612857cd17fd4377d1