当一个新的视图控制器被推送到导航控制器时,将一个子视图保持在屏幕上的同一位置?
Posted
技术标签:
【中文标题】当一个新的视图控制器被推送到导航控制器时,将一个子视图保持在屏幕上的同一位置?【英文标题】:Keep one subview in the same place on the screen while a new viewcontroller is pushed to the navigation controller? 【发布时间】:2012-05-12 20:43:36 【问题描述】:我有一个带有许多图像按钮的“主屏幕”。点击其中一个按钮后,一个详细视图控制器被推到导航控制器上。但是,从视觉上看,我希望按钮中的图像保持在屏幕上的同一位置,而新的视图控制器会过渡到它后面的位置。
模态控制器的一个例子是将照片添加到电子邮件或消息中。您在图库中选择的照片会变大(好像它正在向您移动),而撰写消息视图在后台滑动到位,然后照片缩小到消息视图上的适当位置。
我想到的几个选项:
点击按钮后,将图像放置在屏幕上与 UIWindow 的子视图相同的位置。做动画/过渡,然后使图像成为新视图控制器视图的子视图。
与上述相同,但具有清晰背景的模态视图控制器
让 UINavigationController 成为子视图,并使用 UINavigationController 的父视图执行上述操作
上面的所有选项都是相似的,但我很好奇是否有更好的方法来做到这一点,以及代码的位置。我应该继承 UINavigationController 并将转换代码放在那里吗?或者可能是 AppDelegate(不过,这似乎是错误的)?
【问题讨论】:
【参考方案1】:我会向导航控制器或窗口添加子视图,但需要一些视图层次结构。
您需要为master
和detail
视图控制器提供一种方法来引用imageView
一个ivar 应该没问题。
// PSMasterViewController.m
@interface PSMasterViewController ()
@property (nonatomic, strong) UIImageView *imageView;
@end
@implementation PSMasterViewController
@synthesize imageView = _imageView;
// ...
@end
我已将其放入实现中,因为我不想将其公开给主视图控制器,但您的需求可能会有所不同。
detailViewController
也一样
// PSDetailViewController.h
@interface PSMasterViewController : UIViewController
@property (nonatomic, strong) UIImageView *imageView;
@end
// PSDetailViewController.m
@implementation PSDetailViewController
@synthesize imageView = _imageView;
// ...
@end
现在假设 imageView 已经创建并呈现在主视图控制器中,我们需要在即将推送时实现一些视图体操
- (void)methodThatPushesTheNextViewController;
CGRect destinationFrame = [self.view convertRect:self.imageView.frame toView:self.navigationController.view];
[self.imageView removeFromSuperview];
[self.navigationController.view addSubview:self.imageView];
self.imageView.frame = destinationFrame;
PSDetailViewController *detailViewController = [[PSDetailViewController alloc] init];
detailViewController.imageView = self.imageView;
self.imageView = nil; // The detailViewController should own this now
[self.navigationController pushViewController:detailViewController animated:YES];
现在在细节视图控制器中,我们需要做与我们刚刚做的相反的事情,viewDidAppear:
是一个好地方,尤其是你提到你可能想要移动和缩放
- (void)viewDidAppear:(BOOL)animated;
[super viewDidAppear:animated];
CGRect startFrame = [self.view convertRect:self.imageView.frame fromView:self.navigationController.view];
[self.imageView removeFromSuperview];
[self.view addSubview:self.imageView];
self.imageView.frame = startFrame;
[UIView animateWithDuration:0.25f
animations:^
self.imageView.frame = [self someNewFrame];
];
【讨论】:
我做了一些小改动,但是效果很好……谢谢! 我一直想做这件事。 @Paul.s 技术不再适用于 ios7+。所以对于 7 岁以上的人,我们需要使用自定义转换。在 animateTransition 方法中,我们通常将 toViewController.view 作为子视图添加到 containerView,然后将 imageView 作为子视图添加到 containerView。【参考方案2】:选项 1
你也可以在没有 ModalViewController 的情况下做到这一点。首先要记住,您必须删除图像并再次将其移至 pushViewController,因为如果发生视图转换,则会再次添加新的 viewController,并且您之前的视图会消失。 因此,通过向被推送的 viewController 发送 NSNotification 并创建具有相同帧的视图来执行此操作。还记得在推送新的 ViewController 之前从 superview 中删除视图。
选项2
如果你所有需要相关视图的viewcontrollers都继承自一个ViewController子类,你可以调用[super init]方法创建视图并添加到viewDidLoad方法中。
【讨论】:
【参考方案3】:您可以按照自己的设想在视图上进行“UIView Animation”,也可以使用 iCarousel 来获得更清晰的动画icarousel SourceCode
【讨论】:
以上是关于当一个新的视图控制器被推送到导航控制器时,将一个子视图保持在屏幕上的同一位置?的主要内容,如果未能解决你的问题,请参考以下文章
当 hidesBottomBarWhenPushed = YES 状态恢复时,导航控制器不隐藏标签栏
当 UISearchController 处于活动状态时呈现 UIAlertController