Last active
June 21, 2024 05:12
-
-
Save stefanceriu/5ff0c67e98ae44612857cd17fd4377d1 to your computer and use it in GitHub Desktop.
Enabled iOS style UICollectionView multiple selection on Catalyst applications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UICollectionView+CTX.h | |
// EFClass-Mac | |
// | |
// Created by Stefan Ceriu on 29/11/2019. | |
// Copyright © 2019 EF Education First. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@interface UICollectionView (CTX) | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UICollectionView+CTX.m | |
// EFClass-Mac | |
// | |
// Created by Stefan Ceriu on 29/11/2019. | |
// Copyright © 2019 EF Education First. All rights reserved. | |
// | |
#import "UICollectionView+CTX.h" | |
#import <objc/runtime.h> | |
static void * CTXSelectedItemIndexPathPropertyKey = &CTXSelectedItemIndexPathPropertyKey; | |
@interface UICollectionView () | |
@property (nonatomic, strong) NSIndexPath *ctx_selectedItemIndexPath; | |
@end | |
@implementation UICollectionView (CTX) | |
+ (void)load | |
{ | |
#if TARGET_OS_MACCATALYST | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
CTXSwizzleInstanceMethod([self class], NSSelectorFromString(@"_userSelectItemAtIndexPath:"), @selector(ctx_userSelectItemAtIndexPath:)); | |
CTXSwizzleInstanceMethod([self class], NSSelectorFromString(@"_deselectAllAnimated:notifyDelegate:"), @selector(ctx_deselectAllAnimated:notifyDelegate:)); | |
CTXSwizzleInstanceMethod([self class], NSSelectorFromString(@"_deselectItemAtIndexPath:animated:notifyDelegate:"), | |
@selector(ctx_deselectItemAtIndexPath:animated:notifyDelegate:)); | |
}); | |
#endif | |
} | |
- (void)ctx_userSelectItemAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
self.ctx_selectedItemIndexPath = indexPath; | |
[self ctx_userSelectItemAtIndexPath:indexPath]; | |
} | |
- (void)ctx_deselectAllAnimated:(BOOL)animated notifyDelegate:(BOOL)notifyDelegate | |
{ | |
if(self.ctx_selectedItemIndexPath && [self.indexPathsForSelectedItems containsObject:self.ctx_selectedItemIndexPath]) { | |
if([self.delegate respondsToSelector:@selector(collectionView:shouldDeselectItemAtIndexPath:)]) { | |
if([self.delegate collectionView:self shouldDeselectItemAtIndexPath:self.ctx_selectedItemIndexPath]) { | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
[self ctx_deselectItemAtIndexPath:self.ctx_selectedItemIndexPath animated:animated notifyDelegate:YES]; | |
self.ctx_selectedItemIndexPath = nil; | |
}); | |
} | |
} | |
} | |
} | |
- (void)ctx_deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated notifyDelegate:(BOOL)notifyDelegate | |
{ | |
[self ctx_deselectItemAtIndexPath:indexPath animated:animated notifyDelegate:notifyDelegate]; | |
} | |
- (NSIndexPath *)ctx_selectedItemIndexPath | |
{ | |
return objc_getAssociatedObject(self, CTXSelectedItemIndexPathPropertyKey); | |
} | |
- (void)setCtx_selectedItemIndexPath:(NSIndexPath *)unicorn { | |
objc_setAssociatedObject(self, CTXSelectedItemIndexPathPropertyKey, unicorn, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
static void CTXSwizzleInstanceMethod(Class class, SEL originalSelector, SEL swizzledSelector) { | |
Method originalMethod = class_getInstanceMethod(class, originalSelector); | |
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); | |
if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) { | |
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); | |
} else { | |
method_exchangeImplementations(originalMethod, swizzledMethod); | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was working great for me but something seems to have changed recently. I've just run my app on Xcode 13.3.1 and macOS 12.3.1 and
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
is no longer being called when this swizzling is being done. I also ran into problems with indexPathsForSelectedItems returning multiple values on CollectionViews where allowsMultipleSelection is false.