ナビゲーション バーの下に表示されるアップロード プログレス バーまたは類似のものを配置しようとしていると思いますが、どのビューに移動しても表示されます。私はこれを数週間前に実装しましたが、追加の注意事項がありました。IIViewDeck を使用しているため、UINavigationController 全体の変更も処理できる必要がありました。
私がしたことは、ビューをナビゲーション バーのサブビューとして追加することでした。私のナビゲーション バーとナビゲーション コントローラーは両方ともサブクラス化されています (そして、アプリは問題なく App Store に提出されています)。最初は、ナビゲーション バーをカスタマイズする必要があったため、UIAppearance
これを行いましたが、このようなタスクにかなりの柔軟性を与えてくれるので、今では贈り物のように思えます。
- カスタマイズされた UINavigationController と UINavigationBar を作成する
- タッチを処理する必要がある場合は、実装する必要があります
hitTest:withEvent
。そのコードも以下に含めました。
- ビューが変化するアプリ
UINavigationController
(タブバーアプリ、またはUINavigationController
中央にあるものを変更できるサイドメニューなど)がある場合、進行状況ビューが「フォロー」できるように、中央のビューコントローラーを監視するKVOを実装しましたその周り。コードも下にあります。
これは、カスタム UINavigationController と UINavigationBar を作成する方法です。
+ (ZNavigationController *)customizedNavigationController
{
//This is just a regular UINavigationBar subclass - doesn't have to have any code but I personally override the pop/push methods to call my own flavor of viewWill/Did/Appear/Disappear methods - iOS has always been a bit finicky about what gets called when
ZNavigationController *navController = [[ZNavigationController alloc] initWithNibName:nil bundle:nil];
// Ensure the UINavigationBar is created so that it can be archived. If we do not access the
// navigation bar then it will not be allocated, and thus, it will not be archived by the
// NSKeyedArchvier.
[navController navigationBar];
// Archive the navigation controller.
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:navController forKey:@"root"];
[archiver finishEncoding];
// Unarchive the navigation controller and ensure that our UINavigationBar subclass is used.
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[unarchiver setClass:[ZNavigationBar class] forClassName:@"UINavigationBar"];
ZNavigationController *customizedNavController = [unarchiver decodeObjectForKey:@"root"];
[unarchiver finishDecoding];
// Modify the navigation bar to have a background image.
ZNavigationBar *navBar = (ZNavigationBar *)[customizedNavController navigationBar];
[navBar setTintColor:kZodioColorBlue];
[navBar setBackgroundImage:[UIImage imageNamed:@"Home_TopBar_RoundCorner_withLogo"] forBarMetrics:UIBarMetricsDefault];
return customizedNavController;
}
これで、独自のカスタムZNavigationBar
(これらは私のコードの実際の名前です。すべてを変更するのは大変でした) で、タッチ処理を実装します。変数名は一目瞭然です。この進行状況バーの「アクセサリ ビュー」、「メイン エリア」、または「右側のアクセサリ ビュー」:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
DDLogVerbose(@"Got a touch at point X: %f Y: %f", point.x, point.y);
//First check if the progress view is visible and touch is within that frame
if ([[JGUploadManager sharedManager] progressViewVisible] &&
CGRectContainsPoint([[JGUploadManager sharedManager] uploadProgressView].frame, point))
{
//Modified frame - have to compensate for actual position of buttons in the view from the standpoint of the UINavigationBar. Can probably use another/smarter method to do this.
CGRect modifiedCancelButtonFrame = [[JGUploadManager sharedManager] uploadProgressView].leftAccessoryFrame;
modifiedCancelButtonFrame.origin.y += [[JGUploadManager sharedManager] uploadProgressView].leftAccessoryView.superview.frame.origin.y;
//Do the same thing for the right view
CGRect modifiedRetryButtonFrame = [[JGUploadManager sharedManager] uploadProgressView].rightAccessoryFrame;
modifiedRetryButtonFrame.origin.y += [[JGUploadManager sharedManager] uploadProgressView].rightAccessoryView.superview.frame.origin.y;
//Touch is on the left button
if ([[JGUploadManager sharedManager] progressViewVisible] &&
[[JGUploadManager sharedManager] uploadProgressView].leftAccessoryView &&
CGRectContainsPoint(modifiedCancelButtonFrame, point))
{
return [[JGUploadManager sharedManager] uploadProgressView].leftAccessoryView;
}
//Touch is on the right button
else if ([[JGUploadManager sharedManager] progressViewVisible] &&
[[JGUploadManager sharedManager] uploadProgressView].rightAccessoryView &&
CGRectContainsPoint(modifiedRetryButtonFrame, point))
{
return [[JGUploadManager sharedManager] uploadProgressView].rightAccessoryView;
}
//Touch is in the main/center area
else
{
return [[JGUploadManager sharedManager] uploadProgressView];
}
}
//Touch is not in the progress view, pass to super
else
{
return [super hitTest:point withEvent:event];
}
}
これで、ナビゲーション コントローラーに「続く」KVO パーツができました。KVO をどこかに実装します。シングルトンの「アップロード マネージャー」クラスを使用し、そのクラスの init に配置しますが、それはアプリの設計次第です。
ZRootViewController *rootViewController = ((JGAppDelegate*)[UIApplication sharedApplication].delegate).rootViewDeckController;
[rootViewController addObserver:sharedManager
forKeyPath:@"centerController"
options:NSKeyValueObservingOptionNew
context:nil];
次に、もちろんこれを実装します。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
DDLogVerbose(@"KVO shows something changed: %@", keyPath);
if ([keyPath isEqualToString:@"centerController"])
{
DDLogVerbose(@"Center controller changed to: %@", object);
[self centerViewControllerChanged];
}
}
そして最後にcenterViewControllerChanged
関数:
- (void)centerViewControllerChanged
{
ZRootViewController *rootViewController = ((JGAppDelegate*)[UIApplication sharedApplication].delegate).rootViewDeckController;
ZNavigationController *centerController = (ZNavigationController *)rootViewController.centerController;
//Check if the upload progress view is visible and/or active
if (self.uploadProgressView.frame.origin.y > 0 && self.uploadProgressView.activityIndicatorView.isAnimating)
{
[centerController.navigationBar addSubview:self.uploadProgressView];
}
//Keep weak pointer to center controller for other stuff
DDLogVerbose(@"Setting center view controller: %@", centerController);
self.centerViewController = centerController;
}
私があなたの質問を誤解した場合、私は世界で最も長いSOの回答を入力しましたが、無駄でした. これがお役に立てば幸いです。説明が必要な部分があればお知らせください。