gpt4 book ai didi

ios - 如何像这样在 IOS 中从底部呈现模态 UIViewController 对话框(附图片)

转载 作者:行者123 更新时间:2023-11-28 19:33:01 25 4
gpt4 key购买 nike

如何呈现模态的 UIViewController(从 Storyboard说),并从呈现 View Controller 的底部向上滑动。要求是:

  • 从底部向上滑动,宽度与呈现 View Controller 的宽度对齐
  • 不占用整个屏幕或整个父级呈现 View Controller (而是仅在显示自身所需的高度)
  • 可以在不占据整个屏幕的 View Controller 的上下文中显示

enter image description here

最佳答案

我不使用 Storyboard,所以我全部写出来了。您可以将其复制粘贴到一个全新的项目中并运行它以查看它是否正常工作。

您的 PresentingController 需要符合两点。第一个协议(protocol)是:UIViewControllerTransitioningDelegate,它允许 Controller 提供一个自定义的呈现器(在我们下面的例子中就是它自己)。无论您在此处返回什么(无论是自身还是其他对象)都需要符合 UIViewControllerAnimatedTransitioning 并提供自定义动画。对于这个独立的示例,我选择当前的 viewController 作为演示者和动画师。

接下来,它需要遵守协议(protocol):UIViewControllerAnimatedTransitioning,它为任何显示或关闭 Controller 提供自定义动画。

换句话说,当我们显示或关闭一个 viewController 时,UIViewControllerAnimatedTransitioning 协议(protocol)中的 animateTransition 将被调用,以确定子 Controller 应如何动画进入透视或从中关闭视口(viewport)。

示例(带过渡动画):

//
// ViewController.m
// SO
//
// Created by Brandon T on 2017-01-23.
// Copyright © 2017 XIO. All rights reserved.
//

#import "ViewController.h"


//Some view controller that will be presented modally.
//I have coloured it red.
@interface ModalController : UIViewController
@end

@implementation ModalController
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor redColor];
}
@end



//The view controller that will present or dismiss some other view controller modally.
//I have coloured it white.
@interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
@property (nonatomic, assign) bool presentingModalController;
@property (nonnull, nonatomic, strong) ModalController *modalController;
@property (nonnull, nonatomic, strong) UIButton *button;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

//For this example, I add a button to present and dismiss the redViewController.
self.button = [[UIButton alloc] initWithFrame:CGRectMake(15, self.view.center.y - 100, self.view.frame.size.width - 30, 45)];
[self.button setTitle:@"Present" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.button setBackgroundColor:[UIColor lightGrayColor]];
[self.button.layer setCornerRadius:5.0];
[self.button addTarget:self action:@selector(onButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];


//Create the redViewController and set its transitioning delegate to self (this controller will be providing the animation and presenter).
//We also set the style to OverFullScreen because we don't want this controller to disappear.
//When a view controller is presented, the one that presented it usually disappears or gets removed from the hierarchy until the child is dismissed. In the case of alerts, or controllers that need to display OVER the current one, we need to set the modalPresentationStyle.
self.modalController = [[ModalController alloc] init];
self.modalController.transitioningDelegate = self;
self.modalController.modalPresentationStyle = UIModalPresentationOverFullScreen;
}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)onButtonClicked:(UIButton *)button {
if (self.modalController.view.window == nil) {
[self presentViewController:self.modalController animated:YES completion:nil];
[self.button setTitle:@"Dismiss" forState:UIControlStateNormal];

//not a good idea but meh.. I need to keep this example short.
[self.view.window addSubview:self.button];
}
else {
[self.modalController dismissViewControllerAnimated:YES completion:nil];
[self.button setTitle:@"Present" forState:UIControlStateNormal];
[self.view addSubview:self.button];
}
}


//Custom Animations and Presenters.
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
self.presentingModalController = true; //We are presenting the controller.
return self; //Who is animating it? We are.
}

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
self.presentingModalController = false; //We are dismissing the view controller.
return self; //Who animated it? We did.
}

//How fast should it present? I chose 0.5 seconds.
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
return 0.5;
}

//The actual animation code.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
if (self.presentingModalController) {
//If we are presenting, we need to add the new controller's view as a sub-view.

UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

//We need a starting frame for the animation.
CGRect startingFrame = transitionContext.containerView.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.

//We need an end frame for the animation.
CGRect finalFrame = transitionContext.containerView.bounds;
finalFrame.origin.y = finalFrame.size.height - 100; //100 from the bottom of the parent.
finalFrame.size.height = 100; //Present with a size of 100 height.

//Add the controller's view as a subview of the context.
[transitionContext.containerView addSubview:toViewController.view];
[toViewController.view setFrame:startingFrame];

//Start animating from "startFrame" --> "endFrame" with 0.5 seconds duration and no delay. I chose easeIn style.
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[toViewController.view setFrame:finalFrame];
} completion:^(BOOL finished) {
//We are finished animating, complete the transition!
[transitionContext completeTransition:YES];
}];
}
else {
//If we are dismissing the view controller, we need to animate it down the screen and then remove its view from the context.

UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

//We only need one frame. This is the first frame. We are animating from "endFrame" --> "startingFrame" (backwards/reverse animation).
CGRect startingFrame = transitionContext.containerView.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.


//Start the animation with 0.5 seconds duration and I chose easeOut style.
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[fromViewController.view setFrame:startingFrame];
} completion:^(BOOL finished) {

//Remove the view controller's view from the context and complete the transition!
[fromViewController.view removeFromSuperview];
[transitionContext completeTransition:YES];
}];
}
}
@end

示例(没有过渡动画):

//
// ViewController.m
// SO2
//
// Created by Brandon Thomas on 2017-01-23.
// Copyright © 2017 XIO. All rights reserved.
//

#import "ViewController.h"


@interface ModalController : UIViewController
@end

@implementation ModalController
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor redColor];
}
@end



@interface ViewController ()
@property (nonatomic, assign) bool presentingModalController;
@property (nonnull, nonatomic, strong) ModalController *modalController;
@property (nonnull, nonatomic, strong) UIButton *button;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

self.button = [[UIButton alloc] initWithFrame:CGRectMake(15, self.view.center.y - 100, self.view.frame.size.width - 30, 45)];
[self.button setTitle:@"Present" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.button setBackgroundColor:[UIColor lightGrayColor]];
[self.button.layer setCornerRadius:5.0];
[self.button addTarget:self action:@selector(onButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];


self.modalController = [[ModalController alloc] init];
}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)onButtonClicked:(UIButton *)button {
if (self.modalController.view.window == nil) {
//Present
CGRect startingFrame = self.view.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.

CGRect finalFrame = self.view.bounds;
finalFrame.origin.y = finalFrame.size.height - 100; //100 from the bottom of the parent.
finalFrame.size.height = 100; //Present with a size of 100 height.

[self.modalController.view setFrame:startingFrame];

[self.modalController willMoveToParentViewController:self];
[self addChildViewController:self.modalController];
[self.view addSubview:self.modalController.view];
[self.modalController didMoveToParentViewController:self];

[UIView animateWithDuration:0.5 animations:^{
[self.modalController.view setFrame:finalFrame];
} completion:^(BOOL finished) {

}];
}
else {
//Dismiss
CGRect startingFrame = self.view.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.

[UIView animateWithDuration:0.5 animations:^{
[self.modalController.view setFrame:startingFrame];
} completion:^(BOOL finished) {
[self.modalController.view removeFromSuperview];
[self.modalController willMoveToParentViewController:nil];
[self.modalController removeFromParentViewController];
[self.modalController didMoveToParentViewController:nil];
}];
}
}
@end

关于ios - 如何像这样在 IOS 中从底部呈现模态 UIViewController 对话框(附图片),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41818084/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com