-1

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

- 呈现带有自定义动画的 MFMessageComposeViewController。(这是一个模态视图控制器)。

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

为了这个问题,让我们简单地说,第一个 MFMessageComposeViewController 应该从右侧滑入,然后它应该滑到左侧(按下发送按钮时),而新实例从右侧滑入(很像导航控制器的默认推送动画)。

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

4

6 回答 6

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];
            }
        }];
    }];
}
于 2012-10-14T08:32:18.647 回答
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 之类的过渡效果,并直接对作曲家视图属性进行转换调整,但这也没有多大作用。

一切都在沸腾:

重要提示:消息组合接口本身不可自定义,并且不得由您的应用程序修改。此外,在呈现界面后,您的应用程序无法对 SMS 内容进行进一步的更改。用户可以使用界面编辑内容,但程序更改会被忽略。因此,如果需要,您必须在呈现界面之前设置内容字段的值

编辑:实际上我想我可能已经找到了一种方法来完成这项工作。您似乎仍然不太可能使用任何类型的自定义转换,而且我不能保证 Apple 会批准这一点,但这应该允许您展示 composer 导航控制器推送样式!

而不是使用:

[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;
    }
}

链接下载我在其中制作的项目。

于 2012-10-12T23:05:45.460 回答
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 并且不支持推送导航控制器。

于 2012-10-10T11:05:28.713 回答
0

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

于 2012-10-11T05:32:51.997 回答
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
    })
}

}

瞧,一切都像魅力一样!

于 2019-06-28T19:53:58.520 回答
-1

它是可能的,并且你可以将它用作普通的 ViewController,在我使用的一个应用程序中,modalTransistion 样式作为溶解并且它在存储中......

还有一件事,开发人员决定如何呈现邮件编写器,以及如何关闭它。

由我们而不是 iOS/Apple 处理的呈现和解散。

于 2012-10-04T06:22:03.583 回答