在iOS6中使用QLPreviewController创建自定义navigationItem按钮

11

我的目标是在iPad应用程序中使用QLPreviewController,使用自定义操作项按钮位于顶部工具栏。 在iOS5.1之前我有一个解决方案。我使用了一个扩展QLPreviewController的类,在组件生命周期期间执行了类似以下的操作:

[[self navigationItem] setRightBarButtonItems:[NSArray arrayWithObject:[self buildCustomButton]]];

iOS6之后,这个技巧不再起作用,现在似乎无法改变navigationItem的配置。我认为引入UIActivity和Social Framework可能会产生影响,并且也许不再有效地使用navigationItem,但是我找不到任何解决方案。

有什么建议吗?

谢谢,再见。


类似问题:http://stackoverflow.com/questions/12568508/custom-view-in-tab-bar-does-no-longer-work-in-ios6 - Mark
我有同样的问题。正在尝试解决... - Denis Kutlubaev
遇到了同样的问题。似乎无法替换或删除标准分享按钮了。 - Aron
是的,我曾经能够这样做,因为我将QLpreviewController包装在NavigationController中,但现在当我这样做时,文档不会显示。去想吧 =/ - valheru
5个回答

7
我真的非常需要一个解决方案,所以我想出了这个办法。 是的,它很丑。是的,它可能随时会崩溃。是的,我会直接去开发地狱,但是我的老板现在并没有用愤怒的眼神盯着我...至少暂时没有。
@implementation UINavigationItem (Custom)

void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL);

- (void) override_setRightBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated{   
    if (item && [item.target isKindOfClass:[QLPreviewController class]] && item.action == @selector(actionButtonTapped:)){
        QLPreviewController* qlpc = (QLPreviewController*)item.target;
        [self override_setRightBarButtonItem:qlpc.navigationItem.rightBarButtonItem animated: animated];
    }else{
        [self override_setRightBarButtonItem:item animated: animated];
    }
}

+ (void)load {
    MethodSwizzle(self, @selector(setRightBarButtonItem:animated:), @selector(override_setRightBarButtonItem:animated:));
}

void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) {
    Method origMethod = class_getInstanceMethod(c, origSEL);
    Method overrideMethod = class_getInstanceMethod(c, overrideSEL);

    if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
        class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    }else{
        method_exchangeImplementations(origMethod, overrideMethod);
    }
}

@end

如果我找不到合适的解决方案,Steve Jobs 将会在我的梦中来找我麻烦……

(这段话与IT技术无关)

顺便提一下:我使用的是UIDocumentInteractionController,而不是直接使用QLPreviewController。 - tougher
1
如果您想要移除操作按钮,则将 qlpc.navigationItem.rightBarButtonItem 更改为 nil - tougher
1
你不需要因为苹果没有提供适当的API来进行自定义而道歉... - HyBRiD
我该如何使用您的代码添加新的UIBarButtonItem? - Nam Vu

3

好消息和坏消息我都有。

好消息是我找出了为什么它没有工作。 在iOS6中,QLPreviewController的navigationItem不再具有navigationBar:

(lldb) po [[self navigationItem] navigationBar];
(id) $2 = 0x00000000 <nil>

导航栏现在位于QLPreviewControllersView的视图层次结构深处:

QLPreviewViewController.view->UIView->UIView->QLRemotePreviewContentController->navBar->navItem->rightBarButtonItems。

您可以使用以下方法查找所需的navigationItem:

- (void)inspectSubviewsForView:(UIView *)view
{
    for (UIView *subview in view.subviews)
    {  
        if ([subview isKindOfClass:[UINavigationBar class]])
        {
            UINavigationBar *bar = (UINavigationBar *)subview;
            if ([[bar items] count] > 0)
            {
                UINavigationItem *navItem = [[bar items] objectAtIndex:0];
                [navItem setRightBarButtonItem:nil];
            }
        }

        if ([subview isKindOfClass:[UIView class]] && [[subview subviews] count] > 0)
        {
            [self inspectSubviewsForView:subview];
        }
    }
}

只需将[self view]传递给该方法,它将循环直到找到相关的标签栏。然后,您可以删除或添加自己的标签栏。
坏消息是,您正在访问私有API,使用此功能可能会导致您的应用程序被应用商店拒绝。但这是我见过的唯一答案。希望看到是否有非私有方式来实现此操作,但考虑到其设置方式,这似乎不太可能。
此方法仅在标签栏已就位后调用才有效。最好从“viewDidAppear”中调用此方法,但它并非始终有效。

在UIDocumentInteractionController中,QLPreviewController只有QLPreviewViewController.view->UIView,所以必须继续使用我的hacky类别解决方案:-/ - tougher
是的,我无法在任何子视图中找到UINavigationBars。我甚至尝试过去super.view.subviews(因为我是QLPreviewController的子类)。 - valheru

2

如果您要更改顶部工具栏中的动作项按钮,则必须在内部执行此操作。

-(void)viewDidAppear:(BOOL)animated{
    //add code necessarry to change your action buttons of toptoolbar in quicklook
}

视图出现后,可以访问rightBarButtonItems


2
rightBarButton会在pdf加载完成后出现。因此有时会失败。 - Steven Jiang
无效,对导航栏和/或导航项的任何操作都没有任何影响。 - Kappe

1
最好的方法是实现自己的控制器并使用QLPreviewController的视图作为子视图。在这种情况下,您可以创建自己的带有自定义项的导航栏。

0

我试了很长时间来替换这个按钮。查看了子视图等。似乎这个操作/共享按钮被放置为导航栏的一层。最终我通过在 QLPreviewController 子类中添加一个新按钮来解决了这个问题。

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Button in center of Navigation Bar
    UISegmentedControl *button = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:LS(@"Save"), nil]];
    button.frame = CGRectMake(0, 0, 100, 30);
    button.center = self.view.center;
    button.momentary = YES;
    button.segmentedControlStyle = UISegmentedControlStyleBar;
    button.tintColor = [UIColor colorWithHue:0.6 saturation:0.33 brightness:0.69 alpha:0];
    [button addTarget:self action:@selector(saveToDocumentsClicked) forControlEvents:UIControlEventValueChanged];
    self.navigationItem.titleView = button;
}

我找到的一个解决方法是将QLPreviewController作为全屏子视图添加到我的UIViewController中,再加上一个UINavigationBar,我可以根据自己的喜好进行设置。现在需要明白的是当用户点击QLPreviewController时,如何隐藏和显示导航栏。我尝试使用标准的uiviewcontroller方法(touchesBegan,touchesMove,touchesMove)以及手势管理器,但似乎很难拦截用户点击该组件的事件。 - bovello

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接