协议和委托不适用于 UICollectionReusableView

Posted

技术标签:

【中文标题】协议和委托不适用于 UICollectionReusableView【英文标题】:Protocols and Delegates not working with UICollectionReusableView 【发布时间】:2015-11-20 12:20:20 【问题描述】:

我有一个启用了节页脚的UICollectionView。我创建了一个名为LeafletFooterViewUICollectionReusableView 的自定义子类,并声明了一些IBOutlets 和IBActions:

- (IBAction)dropboxButton:(id)sender;
- (IBAction)soundcloudButton:(id)sender;

在我的UICollectionViewClass 中,我有:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

    UICollectionReusableView *reusableview = nil;

    if (kind == UICollectionElementKindSectionFooter) 
        UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];

        reusableview = footerview;
    

    return reusableview;

LeafletFooterView 类的IBAction 中,我只是想呈现另一个viewController

- (IBAction)dropboxButton:(id)sender

    VideoWebViewController *video = [[VideoWebViewController alloc] init];
    UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:video];

    [self presentViewController:navigation animated:YES completion:nil];

    [video setSelectedVideo:@"https://www.dropbox.com/"];

错误是:

No visible @interface for 'LeafletFooterView' declares the selector 'presentViewController:animated:completion'. 

我已经在IBAction 方法中尝试了[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"www.dropbox.com"]];,虽然现在没有错误,但单击它不会打开带有网站的Safari。该方法肯定被调用; NSLogBreakpoint 证明了这一点。

更新

因此,在那之后不起作用,我尝试为此声明 Delegates 的过程,与这个问题的方式大致相同:Present view controller from NSObject subclass。

这是我的LeafletFooterView

@class LeafletFooterView;
@protocol FooterViewDelegate <NSObject>
-(void)rowTapped;
@end
@interface LeafletFooterView : UICollectionReusableView
@property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)dropboxButton:(id)sender;
@property(nonatomic,assign)id<FooterViewDelegate> delegate;

The LeafletFooterView.m is here: - (IBAction)dropboxButton:(id)sender

    NSLog(@"Dropbox");
    [self.delegate rowTapped];

现在在我的LeafletCollectionViewController,我有:

- (void)rowTapped

    NSLog(@"Is this getting called?");
    VideoWebViewController *video = [[VideoWebViewController alloc] init];
    UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:video];

    [self presentViewController:navigation animated:YES completion:nil];

    [video setSelectedVideo:@"https://www.dropbox.com/"];


当我运行这段代码时,这个方法实际上从未被调用过。 LeafletCollectionView 设置为使用FooterViewDelegate。在LeafletCollectionViewviewWillAppear 中,我尝试了以下操作:

LeafletFooterView *footer = [[LeafletFooterView alloc] init];
footer.delegate = self;

仍然没有真正调用rowTapped 方法。

用户应该能够单击LeafletFooterView 中的UIButton 并显示UIViewController。我该如何实现这一目标?任何指导将不胜感激。

【问题讨论】:

【参考方案1】:

您需要在您的dataSource 所在的位置显示UINavigationController。因此,如果您尝试删除 IBAction 并以编程方式将方法添加到您的数据源要呈现 VideoWebViewController 的任何位置。

然后在您的viewForSupplementaryElementOfKind 方法中,您将访问按钮并触发该方法。所以突然想起来了(有一段时间没用过objC了):

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

    UICollectionReusableView *reusableview = nil;

    if (kind == UICollectionElementKindSectionFooter) 
        LeafletFooterView *footerview = (LeafletFooterView *)[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
        [footerView.dropboxButton addTarget:self
                       action:@selector(dropboxTapped:)
             forControlEvents:UIControlEventTouchUpInside];

        reusableview = footerview;
    

    return reusableview;


-(void)dropboxTapped:(id)sender
    // Present the controller here

我希望这会有所帮助:)

编辑:更新您的问题后,我发现您选择了不同的路线。您只需要为 footerView 设置委托,如下所示:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

    UICollectionReusableView *reusableview = nil;

    if (kind == UICollectionElementKindSectionFooter) 
        LeafletFooterView *footerview = (LeafletFooterView *)[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
        [footerView.dropboxButton addTarget:self
                                     action:@selector(dropboxTapped:)
                           forControlEvents:UIControlEventTouchUpInside];
        footerView.delegate = self
        reusableview = footerview;
    

    return reusableview;

另外,不要忘记将视图投射到 LeafletFooterView,就像我在代码中使用 (LeafletFooterView *) 所做的那样,我希望它有效 :)

【讨论】:

谢谢伙计——这非常有帮助,而且说得通。我只是不太确定“因此,如果您尝试删除该 IBAction,而是以编程方式向您的数据源要呈现 VideoWebViewController 的任何人添加一个方法”.. 我不太确定该做什么 @amitsbajaj 当然,删除 IBAction(在界面生成器中,单击按钮,然后是插座,然后是操作的十字),然后尝试上面的代码 嘿@daven - 抱歉 - 我认为代码有效,但我明确调用该方法进行测试,我忘记了取出该代码。此处的代码在您的回答中为我生成了一个错误,因为 footerView 没有对 .dropboxButton 等的引用。无论如何,我不得不在此处重新打开此案例。我已经使用代表更新了我的问题,以尝试使其正常工作。或者,如果您能够参考如何调用 dropboxButton 等来更新您的答案,那也可以。再次感谢! 这就像一个魅力! footerView.delegate 是这里的关键,因为我将该委托设置在错误的位置并且带有断点,它只是一直显示该委托为零。这就像一个魅力,这真的很有帮助!谢谢男人 - 绝对接受和投票:)

以上是关于协议和委托不适用于 UICollectionReusableView的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UINavigationController 中使用协议和委托

AppDelegate 中的 UIActivityView 使用协议和委托

如何在 Swift 中正确实现不同视图控制器之间的协议和委托?

swift - 我的协议和代表不工作

协议和代表不起作用..我做错了啥?

测量协议和两个跟踪 ID