UIModalTransitionStylePartialCurl 与 UITabBarController

发布于 2024-11-27 03:15:49 字数 890 浏览 7 评论 0原文

这个问题已经被问了很多,例如这里 但据我所知,尚未得到完整答复。

我有一个 UITabBarController ,其中一个 UINavigationController 作为其中一个选项卡的根 vc,它本身有一个 MKMapView 作为其根 vc。我想要的行为是地图部分向上卷曲,同时将选项卡栏保留在适当的位置(类似于地图应用程序)。

到目前为止,我所做的只是使整个视图卷曲,这不太好。

我见过的解决方案是将 hidesBottomBarWhenPushed 属性设置为 NO,这很有意义,但这似乎不起作用(除非我做错了什么)。

为了清楚起见,我的代码如下:

MyVC *aView = [MyVC init];
aView.modalTransitionStyle = UIModalTransitionStylePartialCurl;
aView.hidesBottomBarWhenPushed = NO;

对于演示部分,我尝试了下面的两种选择,但似乎都不起作用:

[self presentModalViewController:updateStatus animated:YES];
[[self navigationController] presentModalViewController:updateStatus animated:YES];

非常感谢任何帮助。

This question has been asked a lot e.g. here but as far as I can see is yet to be answered in full.

I have a UITabBarController with a UINavigationController as the root vc for one of the tabs, which itself has a MKMapView as its root vc. The behaviour I want is for the map to partially curl upwards, while leaving the tab bar in place (similar to the Maps app).

So far all I have managed to get working is for the whole view to curl, which isn't as nice.

Solutions I have seen are to set the hidesBottomBarWhenPushed property to NO, which would make sense however this doesn't seem to work, (unless I am doing something wrong).

For clarity, my code is as follows:

MyVC *aView = [MyVC init];
aView.modalTransitionStyle = UIModalTransitionStylePartialCurl;
aView.hidesBottomBarWhenPushed = NO;

For the presenting part, I have tried the two alternatives below, neither of which seem to work:

[self presentModalViewController:updateStatus animated:YES];
[[self navigationController] presentModalViewController:updateStatus animated:YES];

Any help much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤独患者 2024-12-04 03:15:50

我在 StackOverflow(和互联网)上搜索了这个问题的解决方案。这个问题已经被问过很多次了,但正如你所注意到的,从未得到充分的回答。如果下部工具栏是否卷起并不重要,许多解决方案都会提供可接受的解决方案。

其他提供了使用UIView动画的解决方案/ CoreAnimation 而不是 UIModalTransitionStylePartialCurl 作为模态转换样式;这在最坏的情况下是 App Store 不允许的解决方案,在最好的情况下与从 UIModalTransitionStylePartialCurl 获得的效果并不完全相同(例如,卷曲的形状不同)。

这些解决方案都没有提供模仿 Apple 在地图应用中的解决方案的答案(即使用 UIModalTransitionStylePartialCurl 但在屏幕底部留下不卷曲的 UIToolbar)。

我将继续这种不完整答案的传统,因为您询问了 UITabBarController 并且我的解决方案没有专门解决这种情况。然而,它确实解决了我遇到的问题,即卷曲半页,底部有一个不卷曲的工具栏。

必须有一种更优雅的方法来做到这一点,但这就是我的方法。

我的 AppDelegaterootViewControllerUIViewController 的子类,我将其称为 TAContainerViewControllerTAContainerViewController 管理 a) 屏幕的实际内容(“要卷曲的内容”)、TAContentViewController,以及 b) TAContentViewController<“后面”的内容/code>(例如设置),我将其称为TAUnderCurlViewController

我的 TAContainerViewController 实例具有 TAContentViewController 和 TAUnderCurlViewController 的属性。我的内容 UIViewTAContentViewControllerview 属性的子视图;同样,用户在curl下看到的是TAUnderCurlViewControllerview属性。

TAContainerViewControllerinit 方法中,我确保执行以下操作:

    _underCurlVC.modalTransitionStyle = UIModalTransitionStylePartialCurl;

为了卷曲内容以在页面下方显示,我设置了一个调用此代码的操作

    [self.contentVC presentModalViewController:self.underCurlVC animated:YES];`

selfTAContainerViewControllercontentVCTAContentViewController 的实例,underCurlVC 是的一个实例TAUnderCurlViewController

要关闭视图,只需[self.contentVC DismissModalViewControllerAnimated:YES];

当模态视图关闭时,contentVC 的框架似乎出现了一些奇怪的情况,因此我在模态视图关闭时手动重置框架。

我在 Github 上发布了一个包含更多详细信息的示例项目。希望有人可以将其转变为稍微更优雅的解决方案,或者将其扩展为与 UINavigationController 或 UITabBarController 一起使用。我认为诀窍是将视图控制器从 Cocoa 子类中明确定义的关系中拉出来,所以也许对那些特殊视图控制器进行子类化就可以做到这一点。

I've scoured StackOverflow (and the Internet) for a solution to this problem. The question has been asked many times, but as you note, never sufficiently answered. Many solutions give an acceptable solution if it is unimportant whether, e.g., a lower toolbar curls up as well.

Others have provided a solution using UIView animations / CoreAnimation rather than UIModalTransitionStylePartialCurl as a modal transition style; this is at worst a solution not allowed in the App Store, and at best is not quite the same effect as one gets from UIModalTransitionStylePartialCurl (e.g. the shape of the curl is different).

None of these solutions have provided an answer that mimics Apple's solution in the Maps app (i.e., using UIModalTransitionStylePartialCurl but leaving an un-curled UIToolbar at the bottom of the screen).

I will continue in this tradition of incomplete answers, since you ask about a UITabBarController and my solution doesn't specifically address that case. It does, however, solve the problem I had, which was to get a half page curl with an un-curled toolbar at the bottom.

There must be a more elegant way to do this, but this is how I managed.

The rootViewController of my AppDelegate is a subclass of UIViewController, which I'll call TAContainerViewController. TAContainerViewController manages a) the actual contents of the screen (the "stuff to be curled"), TAContentViewController, and b) the contents "behind" the TAContentViewController (e.g. settings), which I'll call TAUnderCurlViewController.

My instance of TAContainerViewController had properties for a TAContentViewController and a TAUnderCurlViewController. The UIView that was my content was a subview of TAContentViewController's view property; likewise what the user sees under the curl is the view property of the TAUnderCurlViewController.

In the init method of TAContainerViewController I make sure to do the following:

    _underCurlVC.modalTransitionStyle = UIModalTransitionStylePartialCurl;

And to curl the contents to reveal under the page, I set up an action that calls this code:

    [self.contentVC presentModalViewController:self.underCurlVC animated:YES];`

where self is the TAContainerViewController, contentVC is an instance of TAContentViewController, and underCurlVC is an instance of TAUnderCurlViewController.

To dismiss the view, simply [self.contentVC dismissModalViewControllerAnimated:YES];.

Some strangeness seems to occur with the frame of contentVC when the modal view is dismissed, so I manually reset the frame when the modal view is dismissed.

I've posted a sample project with more details on Github. Hopefully someone can take this and turn it into a slightly more elegant solution, or expand it to work with a UINavigationController or UITabBarController. I think the trick is to pull the View Controllers out of the well-defined relationships in the Cocoa subclasses, so maybe subclassing those specialty View Controllers would do it.

在你怀里撒娇 2024-12-04 03:15:50

蒂姆·阿诺德的回应对我来说非常有用,谢谢!

需要注意的一个陷阱:如果您的内容视图控制器添加为容器视图控制器的子级,您的模式页面卷曲转换将占据整个屏幕。您可以不将其添加为子项,但是内容控制器上不会调用任何视图生命周期方法(例如 viewDidLoadviewWillAppear),这可能是问题。

幸运的是,有一种方法可以解决这个问题。在容器控制器中:

  • viewDidLoad 中将内容控制器添加为子级
  • 将其作为 viewDidAppear 中的子级删除
  • viewWillDisappear 中将其重新添加为子级>。

这样,您的内容控制器就可以调用其生命周期方法,同时仍然能够执行模式页面卷曲转换,而无需占用整个屏幕。

这是一个简单解决方案的完整代码:

@interface XXContainerController : UIViewController
@property (strong, nonatomic) UIViewController *contentController;
@property (nonatomic) BOOL curled;
@end

@implementation XXContainerController

@synthesize contentController = _contentController;
@synthesize curled = _curled;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.contentController = [self.storyboard
        instantiateViewControllerWithIdentifier:@"SomeControllerInStoryboard"];

    // Add content controller as child view controller.
    // This way, it will receive all the view lifecycle events
    [self addChildViewController:self.contentController];
    self.contentController.view.frame = self.view.bounds;
    [self.view addSubview:self.contentController.view];
    [self.contentController didMoveToParentViewController:self];    
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Remove the content controller as child view controller.
    // This way, the modal page curl transition will
    // not take over the whole screen.
    // NOTE: need to wait until content controller has appeared
    // (which will happen later).
    // Achieve this by running the code at the end of the animation loop
    [UIView animateWithDuration:0 animations:nil completion:^(BOOL finished) {
        [self.contentController removeFromParentViewController];
    }];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Add the content controller as child view controller again
    // so it receives the view lifecycle events
    [self addChildViewController:self.contentController];
}

- (void)setCurled:(BOOL)curled
{
    if (curled == _curled) return;

    _curled = curled;

    // Curl up the content view and show underneath controller's view
    if (curled) {
        // Note you can specify any modal transition in storyboard
        // E.g. page curl, flip horizontal
        [self.contentController
            performSegueWithIdentifier:@"SomeModalSegueDefinedInStoryboard"
            sender:self];

    // Uncurl and show the content controller's view again
    } else {
        [self.contentController dismissModalViewControllerAnimated:YES];

        // Have to do this, otherwise the content controller's view
        // gets messed up for some reason 
        self.contentController.view.frame = self.view.bounds;
    }
}

@end

Tim Arnold's response worked great for me, thanks!

One trap to watch out for: your modal page-curl transition will take over the whole screen if your content view controller is added as a child of the container view controller. You could just not add it as a child, but then none of the view lifecycle methods will get called on your content controller (e.g. viewDidLoad, viewWillAppear), which could be a problem.

Fortunately, there is a way around this. In your container controller:

  • Add your content controller as a child in viewDidLoad
  • Remove it as a child in viewDidAppear
  • Re-add it as a child in viewWillDisappear.

That way, your content controller gets its lifecycle methods called, while still being able to do a modal page-curl transition without taking up the whole screen.

Here is the entire code of a bare-bones solution:

@interface XXContainerController : UIViewController
@property (strong, nonatomic) UIViewController *contentController;
@property (nonatomic) BOOL curled;
@end

@implementation XXContainerController

@synthesize contentController = _contentController;
@synthesize curled = _curled;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.contentController = [self.storyboard
        instantiateViewControllerWithIdentifier:@"SomeControllerInStoryboard"];

    // Add content controller as child view controller.
    // This way, it will receive all the view lifecycle events
    [self addChildViewController:self.contentController];
    self.contentController.view.frame = self.view.bounds;
    [self.view addSubview:self.contentController.view];
    [self.contentController didMoveToParentViewController:self];    
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Remove the content controller as child view controller.
    // This way, the modal page curl transition will
    // not take over the whole screen.
    // NOTE: need to wait until content controller has appeared
    // (which will happen later).
    // Achieve this by running the code at the end of the animation loop
    [UIView animateWithDuration:0 animations:nil completion:^(BOOL finished) {
        [self.contentController removeFromParentViewController];
    }];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Add the content controller as child view controller again
    // so it receives the view lifecycle events
    [self addChildViewController:self.contentController];
}

- (void)setCurled:(BOOL)curled
{
    if (curled == _curled) return;

    _curled = curled;

    // Curl up the content view and show underneath controller's view
    if (curled) {
        // Note you can specify any modal transition in storyboard
        // E.g. page curl, flip horizontal
        [self.contentController
            performSegueWithIdentifier:@"SomeModalSegueDefinedInStoryboard"
            sender:self];

    // Uncurl and show the content controller's view again
    } else {
        [self.contentController dismissModalViewControllerAnimated:YES];

        // Have to do this, otherwise the content controller's view
        // gets messed up for some reason 
        self.contentController.view.frame = self.view.bounds;
    }
}

@end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文