Custom navigationItem button with QLPreviewController in iOS6
Asked Answered
B

5

11

my goal is to use QLPreviewController in my iPad application for iOS6, using my custom Action item button in the top toolbar. I had solution until iOS5.1. I used a class that extends QLPreviewController and during component lifecycle I did something like

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

With iOS6 this trick doesn't work more, and now it seems impossible change navigationItem configuration. I think that introduction of UIActivity and Social Framework could be involved and maybe it's no more effective to work on navigationItem, but I can find any solution. Any suggestion? Thanks, bye

Banger answered 24/9, 2012 at 15:48 Comment(4)
Similar problem: #12569008Poaceous
I have the same problem. Trying to solve...Nolan
Got the same problem. Can't seem to replace or remove the standard share button anymore.Cas
Yeah, I used to be able to do this because I wrapped the QLpreviewController in a NavigationController but now when I do that, the document won't display. Go figure =/Dendy
L
7

I really really needed a solution, so I made this up.

Yes, it's ugly. Yes, it may break at any time. And yes, I'll go strait to dev hell, but my boss did stop stare at me with angry eyes...for now.

@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 will hunt me in my dreams until I find a proper solution...

Livable answered 4/10, 2012 at 13:54 Comment(4)
BTW: I use an UIDocumentInteractionController, not a QLPreviewController directly.Livable
If you want to remove the action button, then change qlpc.navigationItem.rightBarButtonItem to nil.Livable
You don't need to apologize just because Apple does not provide proper API for customization...Suppositious
How can i add new UIBarButtonItem by using your code?Shewchuk
C
3

Well, i've got good news and bad news.

The good news is i've figured out why this isn't working. In iOS6 the QLPreviewController's navigationItem no longer has a navigationBar:

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

The navigation bar is now located deep within the view hierarchy of the QLPreviewControllersView:

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

You can use the below method to find the navigationItem that you're looking for:

- (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];
        }
    }
}

Simply pass [self view] to that method and it will loop until it finds the tab bar in question. You can then remove or add your own.

The bad news is of course that you are accessing private APIs and use of this will likely get your app rejected by the app store. It is however the only answer i've seen on this. Would love to see if there is a non-private way to do this but given the way it's set up, it seems unlikely.

Also, this method will only work if it is called after the bar is already in position. The best place to call this from is the 'viewDidAppear' but it doesn't work 100% of the time.

Cas answered 4/10, 2012 at 2:4 Comment(2)
In a UIDocumentInteractionController the QLPreviewController only got QLPreviewViewController.view->UIView, so have to keep using my hacky category solution :-/Livable
Yeah I wasn't able to find any UINavigationBars in any of the subviews. I even tried going to super.view.subviews (since I subclass QLPreviewController)Dendy
I
2

It works if you are changing the action item button in top toolbar you would have to do it inside

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

After the view appears rightBarButtonItems can be accessed.

Irenics answered 10/10, 2012 at 12:33 Comment(2)
The rightBarButton appears after the loading of pdf finished.So sometimes it will fail.Rachele
doesn't work, any manipulation to the nav bar and/or nav items here doesn't have any effectBaroda
O
1

The best way is to implement your own controller and use view of QLPreviewController as subview. In that case you can made your own navigation bar with custom items.

Ostiary answered 16/7, 2013 at 11:45 Comment(0)
N
0

I tried for a long time to replace this button. Looked to subviews, etc. Looks like this actions/share button is put as a layer to the nav. bar. I ended up by solving this issue for myself by adding one more button instead of title in QLPreviewController subclass.

- (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;
}
Nolan answered 27/9, 2012 at 16:25 Comment(1)
a workaround I found is adding QLPreviewController as fullscreen subView to my UIViewController, together with a UINavigationBar, tha I can set up as I like. Remain to understand when user tap on QLPreviewController, in order to hide and show navigation bar. I tried with stardard uiviewcontroller methods (touchesBegan, touchesMove, touchesMove) as well as gesture manager, but it seems hard to intercept when user tap on that component.Banger

© 2022 - 2024 — McMap. All rights reserved.