如何在不占满整个屏幕的UIView上使用UIModalTransitionStylePartialCurl?

28
在苹果官方的 iPhone 地图应用中,右下角有一个小“翻页”按钮。当你按下它时,地图本身会翻开,显示一些选项。 我想在自己的应用程序中复制此效果。
我正在尝试使用 UIModalTransitionStylePartialCurl(在SDK 3.2中添加)。在布局方面,我的应用程序几乎完全类似于苹果官方的 Maps 应用程序。我可以轻松地让整个屏幕翻开,露出另一个视图,但我不想要这样。我只想让地图视图翻开。
为了创建这个效果,你必须有一个 UIViewController 来执行过渡。如果我将这个 UIViewController 的视图设置为屏幕上某个不占据整个屏幕的小子视图,那么我就可以让只有该子视图翻开。这很好!但是,在第二部分转换(页面跌回原位)之后,视图永远不会回到起始位置。要么翻开的视图会从其原始位置移动,要么揭示的视图会扩展以占据整个屏幕。
我是否犯了明显的错误?我真的很感激任何帮助!
我正在使用的代码非常简单,基本上只有:
underMapViewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;

[curlableMapViewController presentModalViewController:underMapViewController animated:YES];

1
真的吗?没有任何现有的答案解决了您的问题吗?[咳咳咳] 您可能想要接受至少其中一个,这真的可以帮助人们有动力来帮助您! - Norman H
8个回答

10

根据文档

UIModalTransitionStylePartialCurl

当视图控制器被展示时,当前视图的一个角会卷曲起来,以显示在其下面的模态视图。在关闭时,卷曲的页面会自动展开到模态视图的顶部。使用此过渡类型呈现的模态视图本身无法呈现任何其他模态视图。

仅支持在父视图控制器呈现全屏视图并使用UIModalPresentationFullScreen模态呈现样式的情况下使用此过渡样式。尝试使用不同的形式因素或不同的呈现样式来呈现父视图将会触发异常。

虽然我使用全屏以外的其他呈现方式并没有收到任何异常。我进行了测试,并遇到了与您相同的问题。我发现,如果我的ParentViewController的视图是ImageView,并且我将内容模式设置为UIViewContentModeCenter,则视图不会被调整大小或移动位置。也许有一种解决方法是将当前视图保存为图像,将其置于顶部,使其卷曲,然后在关闭模态视图之后重新排列混乱的隐藏内容并删除顶部图像视图。我知道这听起来很疯狂,但如果我真的必须满足该要求,那就是我会尝试的方法。

希望这可以帮助你,Jorge。


谢谢!我会尝试你建议的技术,并看看能否想出可行的解决方案。 - caecus314

7

这样怎么样:

    [UIView beginAnimations:@"PartialPageCurlEffect" context:nil];
    [UIView setAnimationDuration:0.3];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:myOldSubViewController.view cache:YES];

    [myOldSubViewController.view addSubview:myNewViewController.view];

    [UIView commitAnimations];

注意:对于某些视图,如果它们过于复杂或偏离中心,可能会出现伪影。将cache:YES更改为cache:NO可能会解决问题。

1
这是一个类似的效果,但不是 OP 想要的。这段代码会完全“撕掉”“旧”的视图,而不仅仅是像地图一样稍微“揭开”一点点以显示下面的内容。 - Nick Farina
再读一遍,我可以理解他的意思。也许可以在动画进行到一半时中止它,以便部分显示? - Marius

7

实际上,这比你猜想的要简单得多。

我们将称视图控制器为MapViewControllerSettingsViewController。你的问题是你想要展开MapViewController的一部分(仅此部分)以显示SettingsViewController

这是如何做到的:

  • 使用全尺寸视图来呈现两个视图。
  • 只在SettingsViewController的视图的底部放置内容
  • 像你已经做的那样使用UIModalTransitionStylePartialCurl进行转换。

iOS会自动检测到你已经这样做了,并且只会展开MapViewController的视图,直到SettingsViewController的视图的底部,也就是你所有的内容所在的地方。

如果你把内容放在SettingsViewController的视图的顶部,iOS会检测到这一点,而完全展开MapViewController的视图。

总结:只在新视图的底部放置内容。iOS会解决。

(我认为这些内容没有在任何地方得到记录,抱歉。)


尽管你的回答可能有用,但你所描述的只是“UIModalTransitionStylePartialCurl”的正常行为。@caecus318 面临的问题与在视图底部保持一栏而不进行任何动画并返回到原始状态有关。 - cprcrack
啊哈,直到你解释之前,这个问题对我来说从未有意义。我已经修改了我的答案。(它很有用,所以我不想只是删除它。) - Steven Fisher

5

我有一个小小的问题,对于IT技术感到困惑。

.modalTransitionStyle

并且

.modalPresentationStyle

第一个应该放在目标视图控制器上,例如你想要在下面的那个控制器。第二个应该放在父视图控制器上,例如实际上被卷曲变形的控制器。OP做对了,但我做错了,在我弄清楚之前,这让我感到沮丧了10分钟。在这篇文章中分享出来,以防有人像我一样需要帮助。


0

我也遇到了这个问题。对我来说,父视图的框架直到模态视图被解除后才会变形。因此,在解除之前缓存了框架,然后立即恢复了它。

CGRect frame = controllerWithModal.view.frame;
[controllerWithModal dismissModalViewControllerAnimated:YES];   
controllerWithModal.view.frame = frame;

0

我也遇到了这个问题,但我解决了它...(不知道这是否是正确的方法,但它能工作)

我想在滚动视图中放置一个ImageView,并且当用户点击该滚动视图中的按钮时,我想将滚动视图卷起来并在那个位置显示一个TableView。 因此,我在ScrollView后面放置了一个TableView,并最初将其设置为隐藏。当用户点击按钮时,我执行了以下操作

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:frontView cache:YES];
[UIView commitAnimations];

然后从视图中移除了frontview。 希望这有所帮助。


0
重写您的underMapViewControllerviewWillDisappear方法,类似于以下内容:
- (void)viewWillDisappear:(BOOL)animated
{
    curlableMapViewController.view.frame = CGRectMake(0.f, 0.f, 320.f, 416.f);

    [super viewWillDisappear:animated];
}

这会将 curlableMapViewController 视图的大小纠正为您指定的已知大小,例如您可以在 viewWillAppear 方法中提前保存。


0

我相信苹果的地图应用程序使用了未记录的转换:mapCurl和mapUncurl。我不确定是否有任何方法可以完全满足caecus314的要求(这也是我一直试图复制的效果)。

UIModalTransitionStylePartialCurl会将第一个视图的整个底部部分卷起来,包括工具栏,这与苹果的地图应用程序不同,后者只卷起地图并保留工具栏在原位。

据我所知,没有办法只卷起地图。


当然有方法,事实上,提问的用户已经告诉你如何完成它。你至少读了问题吗?其中有一部分说:“我只能让那个子视图向后撕开。太好了!”与那些甚至没有仔细阅读问题就给出不真实答案的人打交道真的很烦人。很抱歉,但我不得不说。 - cprcrack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接