私はこの問題の解決策を何ヶ月も探し、ついにQLPreviewControllerのナビゲーションバーをカスタマイズする方法を見つけました。以前は、アプリ内の特定の機密ドキュメントのiOS共有ボタンを表示することが許可されていないため、UIWebViewを使用してドキュメントを表示していました。これは、QLPreviewControllerが行うことです。ただし、小さなプレビューなどを含む目次などの優れた機能が必要でした。そこで、このボタンを取り除くための信頼できる方法を探しました。皆さんと同じように、私は最初にQLPreviewControllerのナビゲーションバーのカスタマイズを検討していました。ただし、他の人がすでに指摘しているように、iOS6以降、これは絶対に不可能です。したがって、既存のナビゲーションバーをカスタマイズする代わりに、独自のナビゲーションバーを作成し、それをQLナビゲーションバーの前に配置して非表示にする必要があります。
では、これを行う方法は?まず、QLPreviewContollerをサブクラス化し、viewDidAppearメソッドとviewWillLayoutSubviewsを次のように上書きする必要があります。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.qlNavigationBar = [self getNavigationBarFromView:self.view];
self.overlayNavigationBar = [[UINavigationBar alloc] initWithFrame:[self navigationBarFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]]];
self.overlayNavigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.overlayNavigationBar];
NSAssert(self.qlNavigationBar, @"could not find navigation bar");
if (self.qlNavigationBar) {
[self.qlNavigationBar addObserver:self forKeyPath:@"hidden" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];
}
// Now initialize your custom navigation bar with whatever items you like...
UINavigationItem *item = [[UINavigationItem alloc] initWithTitle:@"Your title goes here"];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonTapped:)];
item.leftBarButtonItem = doneButton;
item.hidesBackButton = YES;
[self.overlayNavigationBar pushNavigationItem:item animated:NO];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.overlayNavigationBar.frame = [self navigationBarFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}
qlNavigationBarは、 QLPreviewControllerが所有するデフォルトのナビゲーションバーです。overlayNavigationBarは、デフォルトのナビゲーションバーを非表示にするカスタムナビゲーションバーです。また、デフォルトのQLナビゲーションバーにキーと値の監視を追加して、デフォルトのナビゲーションバーが非表示/再表示されたときに通知を受け取るようにします。viewWillLayoutSubviewsメソッドでは、カスタムナビゲーションバーフレームを処理します。
次に行うべきことは、クイックルックナビゲーションバーの可視性の変化をリッスンすることです。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// Toggle visiblity of our custom navigation bar according to the ql navigationbar
self.overlayNavigationBar.hidden = self.qlNavigationBar.isHidden;
}
したがって、ここで、QLナビゲーションバーを取得するために必要なメソッドと、カスタムナビゲーションバーの現在のフレームを常に提供するメソッドを実装する必要があります。
- (UINavigationBar*)getNavigationBarFromView:(UIView *)view {
// Find the QL Navigationbar
for (UIView *v in view.subviews) {
if ([v isKindOfClass:[UINavigationBar class]]) {
return (UINavigationBar *)v;
} else {
UINavigationBar *navigationBar = [self getNavigationBarFromView:v];
if (navigationBar) {
return navigationBar;
}
}
}
return nil;
}
- (CGRect)navigationBarFrameForOrientation:(UIInterfaceOrientation)orientation {
// We cannot use the frame of qlNavigationBar as it changes position when hidden, also there seems to be a bug in iOS7 concerning qlNavigationBar height in landscape
return CGRectMake(0.0f, self.isIOS6 ? 20.0f : 0.0f, self.view.bounds.size.width, [self navigationBarHeight:orientation]);
}
- (CGFloat)navigationBarHeight:(UIInterfaceOrientation)orientation {
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if(UIInterfaceOrientationIsLandscape(orientation)) {
return self.isIOS6 ? 32.0f : 52.0f;
} else {
return self.isIOS6 ? 44.0f : 64.0f;
}
} else {
return self.isIOS6 ? 44.0f : 64.0f;
}
}
ほかに何か?もちろん、プロパティを定義し、 deallocでオブザーバーを削除し、iOS6プロパティを定義して設定する必要があります(Webには多くの例があります...)。また、ナビゲーションバーをカスタマイズして、ボタンのコールバックをリッスンする必要があります。それでおしまい。
これは少しハッキーだと思います...デフォルトのQLアクションボタンを別のナビゲーションバーの下に非表示にすることで非表示/置換します...しかし、少なくとも私にとっては信頼性が高く、プライベートAPIなどにアクセスしません。
私は、iOS 6.0〜7.0、およびiPad 2&3、iPhone 4S&5(iOS 7.0 Beta 6がインストールされている後者)で利用可能なすべてのシミュレーターでソリューションをテストしました。