MFMessageComposeViewController:我可以用自定义动画呈现这个吗?

时间:2012-10-04 05:13:58

标签: iphone objective-c ios

这就是我想要做的。不确定是否可能,但如果有一个干净的代码的答案,应用程序商店可以接受我非常乐意为它提供赏金!

- 使用自定义动画呈现MFMessageComposeViewController。 (它的    模态视图控制器)。

- 然后我想用一个动画关闭这个MFMessageComposeViewController的动画    自定义动画,同时在新实例上设置动画    MFMessageComposeController。 (再次,自定义动画)。

为了这个问题,让我们简单一点,并说第一个MFMessageComposeViewController应该从右边滑入,然后它应该向左滑动(当按下发送按钮时)新实例滑动从右边开始(非常类似于导航控制器的默认推送动画)。

如果这是不可能的,那么解释为什么没有办法做到这一点会很棒:)

6 个答案:

答案 0 :(得分:4)

没有。但是你可以做一个技巧,看起来就像你想要的那样。

- (IBAction)showComposer:(id)sender {
    // 1) get the prepared image of empty composer
    UIImageView *composerView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"preparedImage"]];
    composerView.frame = rightOffscreenFrame;
    [self.view addSubview:composerView];
    // 2) do any transitions, and transforms with it
    [UIView animateWithDuration:0.33 animations:^{
        composerView.frame = self.view.bounds;
    } completion:^(BOOL finished) {
        if (finished) {
            // 3) when it is time, just add a real composer without animation
            MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
            composer.mailComposeDelegate = self;
            [self presentViewController:composer animated:NO completion:^{
                [composerView removeFromSuperview];
            }];
        }
    }];

}

- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
    // 4) when user will send message, render the new image with content of composer
    UIGraphicsBeginImageContext(self.view.bounds.size);
    [controller.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImageView *composerView = [[UIImageView alloc] initWithImage:newImage];
    composerView.frame = self.view.bounds;
    // 5) show it below composer, close composer without animation.
    [self.view addSubview:composerView];
    [self dismissViewControllerAnimated:NO completion:^{
        // 6) do any transitions, and transforms with image.
        [UIView animateWithDuration:0.33 animations:^{
            composerView.frame = leftOffscreenFrame
        } completion:^(BOOL finished) {
            if (finished) {
                [composerView removeFromSuperview];
            }
        }];
    }];
}

答案 1 :(得分:3)

好吧,我不得不说你真的很了解我的好奇心。现在,就你的问题而言,它看起来并不像你能做的那么多。

我采用了几种不同的方法来尝试以非默认方式呈现作曲家但收效甚微。我能得到的最接近的是:

UIViewAnimationTransition trans = UIViewAnimationTransitionCurlDown;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:trans forView:[self view] cache:YES];
[self presentViewController:controller animated:NO completion:nil];
[UIView commitAnimations];

使用这种呈现方式,动画效果发生了,但它实际上似乎并不适用于作曲家。这只是一个翻页的空白页面。我也尝试过直接手动添加转换效果(如alpha)和转换调整到composers视图属性,但这也没有做太多。

所有事情都一直沸腾到this

  

重要说明:邮件撰写界面本身不是   可自定义,不得由您的应用程序修改。在   此外,在显示界面后,您的应用程序无法使用   进一步更改SMS内容。用户可以编辑   使用界面的内容,但忽略程序化更改。   因此,您必须先设置内容字段的值(如果需要)   介绍界面

编辑:其实我觉得我可能找到了一种方法来完成这项工作。你似乎不太可能使用任何类型的自定义转换,我不能保证Apple会批准这个,但这应该允许你呈现作曲家导航控制器推送风格!

而不是使用:

[self presentViewController:controller animated:YES completion:nil];

使用:

[self.navigationController pushViewController:[[controller viewControllers] lastObject] animated:YES];

这实际上允许你推送到作曲家。默认情况下,不支持此行为,并导致错误,指出您无法将推送到和导航控制器(作曲家)。

然后跟进,在- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result中使用:

[self.navigationController popToRootViewControllerAnimated:YES];

而不是:

[self dismissViewControllerAnimated:YES completion:nil];

编辑2:抱歉,看起来我忘记了你问题的其中一点。如果要从作曲家的一个实例推送到另一个实例,可以为每个作曲家创建iVar,在viewDidLoad中设置它们,然后在didFinishWithResult中处理它们的雏菊链接。但是,这只能部分地解决问题。按照目前的情况,我在下面发布的代码将在未来很好地工作,但不能备份。我相信这样做的原因是作曲家希望在消息成功发送后关闭并取消,因此取消但会自动禁用。

总的来说,如果你把它搞乱一点,你仍然可以让它运转起来。

 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {

    switch (result) {
        case MessageComposeResultCancelled:
            if (controller == firstComposer) {
                [self.navigationController popToRootViewControllerAnimated:YES];
            }
            else if (controller == secondComposer) {
                [self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
            }

            break;
        case MessageComposeResultFailed:
            NSLog(@"Failed");
            break;
        case MessageComposeResultSent:

            if (controller == firstComposer) {
                [self.navigationController pushViewController:[[secondComposer viewControllers] lastObject] animated:YES];
                [secondComposer becomeFirstResponder];
            }
            break;
        default:
            break;
    }
}

Link to download the project I made this in.

答案 2 :(得分:0)

MFMailComposeViewController 作为模态视图与Apple的HIG一致。将其推送到导航堆栈不是。使用:

-presentModalViewController:animated:

-presentViewController:animated:completion` (if supporting iOS 5).

如果你真的想要一些不同的使用 modalTransitionStyle

mail.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal; 
mail.modalTransitionStyle=UIModalTransitionStyleCoverVertical;
mail.modalTransitionStyle = UIModalTransitionStylePartialCurl; 
mail.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

并使用 modalPresentationStyle

FMailComposeViewController是一个UINavigationController,不支持推送导航控制器。

答案 3 :(得分:0)

我认为这不可能,因为它是Apple提供的自定义组件

答案 4 :(得分:0)

最近面临此任务。我需要实现类似于导航堆栈的推入和弹出的过渡。
这是我的实现:

extension MFMailComposeViewController: UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {

convenience init(_ customTransition: Bool) {
    self.init()
    if customTransition { self.transitioningDelegate = self }
}

public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return self
}

public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return self
}

public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 1.0
}

public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    let containerView = transitionContext.containerView
    guard let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        else { return }

    var start = transitionContext.initialFrame(for:fromVC)
    var end = transitionContext.finalFrame(for:toVC)

    if toVC is MFMailComposeViewController {
        start.origin.x -= containerView.bounds.width
        end.origin.x = 0.0

        let v1 = transitionContext.view(forKey:.from)!
        let v2 = transitionContext.view(forKey:.to)!
        v2.frame.origin.x = containerView.bounds.width

        containerView.addSubview(v2)

        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
            v1.frame.origin.x -= containerView.bounds.width/3
            v2.frame = end
        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }

    } else {
        start.origin.x = containerView.bounds.width
        end.origin.x = 0.0

        let v1 = transitionContext.view(forKey:.from)!
        let v2 = transitionContext.view(forKey:.to)!
        v2.frame.origin.x = -containerView.bounds.width/3

        containerView.insertSubview(v2, belowSubview: v1)

        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
            v2.frame = end
            v1.frame = start
        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

}

上面,我们实现了MFMailComposeViewController的扩展,其中的关键是带有以下行的初始化:self.transitioningDelegate = self
接下来,我们编写控制器的伪代码,其中将初始化MFMailComposeViewController并提供所需的转换:

class ViewController: UIViewController, MFMailComposeViewControllerDelegate {

@IBAction func testAction(_ sender: UIButton) {
    let mailComposerVC = MFMailComposeViewController(true)
     mailComposerVC.mailComposeDelegate = self
    //then we configure the controller for our needs
    self.present(mailComposerVC, animated: true, completion: nil)
}

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {

    controller.dismiss(animated: true, completion: {
       //configure result
    })
}

}

瞧,一切都像魅力一样!

答案 5 :(得分:-1)

它可能,&你可以使用它作为一个普通的ViewController,在我使用的一个应用程序中,modalTransistion样式作为溶解和它在商店......

还有一件事,开发人员决定如何呈现邮件编辑器,以及如何解雇它。

呈现&解雇由我们处理而不是iOS /苹果..