programing

내비게이션 기반 앱에서 푸시 및 팝 애니메이션을 변경하는 방법

golfzon 2023. 4. 14. 22:33
반응형

내비게이션 기반 앱에서 푸시 및 팝 애니메이션을 변경하는 방법

네비게이션 기반의 어플리케이션을 가지고 있는데 푸시 및 팝 애니메이션의 애니메이션을 변경하고 싶습니다.내가 그걸 어떻게 하겠어?

2018년 편집

이 질문에는 많은 답변이 있었고, 꽤 오랜 시간이 흘렀습니다. 저는 지금 가장 관련이 있다고 생각되는 것에 대한 답변을 다시 선택했습니다.다른 의견이 있으면 댓글로 알려주세요.

다음을 수행했는데 잘 작동합니다.간단하고 이해하기 쉽다.

CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
//transition.subtype = kCATransitionFromTop; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[[self navigationController] popViewControllerAnimated:NO];

밀어서도 마찬가지고..


Swift 3.0 버전:

let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
self.navigationController?.view.layer.add(transition, forKey: nil)
_ = self.navigationController?.popToRootViewController(animated: false)

이것이 내가 항상 이 일을 해내는 방법이다.

푸시용:

MainView *nextView=[[MainView alloc] init];
[UIView  beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController:nextView animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];
[nextView release];

팝의 경우:

[UIView  beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
[UIView commitAnimations];

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:0.375];
[self.navigationController popViewControllerAnimated:NO];
[UIView commitAnimations];


아직 많은 피드백을 받고 있기 때문에, 어쨌든 Apple이 추천하는 애니메이션 블록으로 업데이트를 실시합니다.

★★★★★★★★★★★★★★★★★★:

MainView *nextView = [[MainView alloc] init];
[UIView animateWithDuration:0.75
                         animations:^{
                             [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                             [self.navigationController pushViewController:nextView animated:NO];
                             [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
                         }];

의의: :

[UIView animateWithDuration:0.75
                         animations:^{
                             [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                             [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
                         }];
[self.navigationController popViewControllerAnimated:NO];

최신 2022 코드

내비게이션 기반 앱에서 푸시 및 팝 애니메이션을 변경하는 방법...

iOS 개발을 처음 접하는 경우.가장 심플하고 일반적인 애니메이션('슬라이드 오버' 또는 '한쪽이 다른쪽을 누른다' 등)의 경우 엄청난 양의 작업을 수행해야 합니다.

합니다. 커스텀이 필요합니다.UIViewControllerAnimatedTransitioning

  1. 필요하다popStyle -입니까, off입니까? - - - 、 점 boolean 、 ? boolean 、 boolean boolean 、 boolean boolean boolean 。

  2. 다음을 포함해야 합니다.transitionDuration 및 메인콜인 '메인 콜'은animateTransition

  3. 푸시용과 팝용 두 가지 다른 애니메이션 루틴을 작성해야 합니다.안에서.animateTransition는 단순히 popStyle

  4. 다음 예시는 단순한 이동/이동입니다.

  5. 고객님의 고객명animatePush ★★★★★★★★★★★★★★★★★」animatePop루틴."view"와 "to view"를 가져와야 합니다.(그 방법을 코드 예에 나타냅니다).

  6. 그리고 당신은 해야 한다 addSubview츠요시하다

  7. 그리고 당신은 전화해야 한다.completeTransition

복사 붙여넣기 ..

  class SimpleOver: NSObject, UIViewControllerAnimatedTransitioning {
        
        var popStyle: Bool = false
        
        func transitionDuration(
            using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.20
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            if popStyle {
                
                animatePop(using: transitionContext)
                return
            }
            
            let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
            let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            
            let f = transitionContext.finalFrame(for: tz)
            
            let fOff = f.offsetBy(dx: f.width, dy: 55)
            tz.view.frame = fOff
            
            transitionContext.containerView.insertSubview(tz.view, aboveSubview: fz.view)
            
            UIView.animate(
                withDuration: transitionDuration(using: transitionContext),
                animations: {
                    tz.view.frame = f
            }, completion: {_ in 
                    transitionContext.completeTransition(true)
            })
        }
        
        func animatePop(using transitionContext: UIViewControllerContextTransitioning) {
            
            let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
            let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            
            let f = transitionContext.initialFrame(for: fz)
            let fOffPop = f.offsetBy(dx: f.width, dy: 55)
            
            transitionContext.containerView.insertSubview(tz.view, belowSubview: fz.view)
            
            UIView.animate(
                withDuration: transitionDuration(using: transitionContext),
                animations: {
                    fz.view.frame = fOffPop
            }, completion: {_ in 
                    transitionContext.completeTransition(true)
            })
        }
    }

그리고...

2. 뷰 컨트롤러에서 사용합니다.

주의: 이상하게도 이 작업은 "첫 번째" 보기 컨트롤러에서만 수행되어야 합니다. ("아래"에 있는 컨트롤러)

위에 있는 거 가지고는 아무것도 하지 마.만만하다.

그럼 너희 반은...

class SomeScreen: UIViewController {
}

...가 된다.

class FrontScreen: UIViewController,
        UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
    
    let simpleOver = SimpleOver()
    

    override func viewDidLoad() {
        
        super.viewDidLoad()
        navigationController?.delegate = self
    }

    func navigationController(
        _ navigationController: UINavigationController,
        animationControllerFor operation: UINavigationController.Operation,
        from fromVC: UIViewController,
        to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        simpleOver.popStyle = (operation == .pop)
        return simpleOver
    }
}

바로 그겁니다.

아무 변화 없이 그냥 누르고 터집니다.밀다

let n = UIStoryboard(name: "nextScreenStoryboardName", bundle: nil)
          .instantiateViewController(withIdentifier: "nextScreenStoryboardID")
          as! NextScreen
navigationController?.pushViewController(n, animated: true)

다음 화면에서 원하는 대로 팝업을 할 수 있습니다.

class NextScreen: TotallyOrdinaryUIViewController {
    
    @IBAction func userClickedBackOrDismissOrSomethingLikeThat() {
        
        navigationController?.popViewController(animated: true)
    }
}

휴.

밀기 위해

CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionFade;
//transition.subtype = kCATransitionFromTop;

[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController pushViewController:ViewControllerYouWantToPush animated:NO];

팝용

CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionFade;
//transition.subtype = kCATransitionFromTop;

[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];

Swift에서는 내선번호가 확실히 당신의 친구라는 것을 기억하세요!

public extension UINavigationController {

    /**
     Pop current view controller to previous view controller.

     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func pop(transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.popViewControllerAnimated(false)
    }

    /**
     Push a new view controller on the view controllers's stack.

     - parameter vc:       view controller to push.
     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func push(viewController vc: UIViewController, transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.pushViewController(vc, animated: false)
    }

    private func addTransition(transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = type
        self.view.layer.addAnimation(transition, forKey: nil)
    }

}

@Magnus 답변, Swift (2.0)만 해당

    let transition = CATransition()
    transition.duration = 0.5
    transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromTop
    self.navigationController!.view.layer.addAnimation(transition, forKey: nil)
    let writeView : WriteViewController = self.storyboard?.instantiateViewControllerWithIdentifier("WriteView") as! WriteViewController
    self.navigationController?.pushViewController(writeView, animated: false)

일부 측면:

할 수 요, 세구로 요.prepareForSegue ★★★★★★★★★★★★★★★★★」shouldPerformSegueWithIdentifier, 기본 애니메이션도 그대로 유지됩니다.이 문제를 해결하려면 스토리보드로 이동하여 Segue를 클릭한 다음 'Animates' 상자를 선택 해제해야 합니다.그러나 이 경우 IOS 9.0 이상에서는 앱이 제한됩니다(적어도 Xcode 7에서 실행한 경우).

segue에서 수행할 경우 마지막 두 줄을 다음과 같이 교체해야 합니다.

self.navigationController?.popViewControllerAnimated(false)

내가 틀렸다고 해도, 그건 좀 무시해.

애플은 더 이상 개인 통화를 하는 앱을 승인하지 않기 때문에 개인 통화를 사용하는 것은 좋지 않은 생각이다.이걸 시도해 보세요.

//Init Animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.50];


[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.navigationController.view cache:YES];

//Create ViewController
MyViewController *myVC = [[MyViewController alloc] initWith...];

[self.navigationController pushViewController:myVC animated:NO];
[myVC release];

//Start Animation
[UIView commitAnimations];

구글에서 가장 좋은 결과가 나왔기 때문에 iOS 7+ 전환 API를 사용하는 것이 가장 합리적인 방법이라고 생각합니다.iOS 10에서 Swift 3으로 구현했습니다.

은 꽤 간단합니다.UINavigationController는 2개의 간에 애니메이션을 .됩니다.UINavigationController할 수 있습니다.UIViewControllerAnimatedTransitioning프로토콜입니다.

를 들어, 이것은 나의 '아예'입니다.UINavigationController★★★★★★★★★★★★★★★★★★:

class NavigationController: UINavigationController {
    init() {
        super.init(nibName: nil, bundle: nil)

        delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension NavigationController: UINavigationControllerDelegate {

    public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return NavigationControllerAnimation(operation: operation)
    }

}

「 」가 을 알 수 .UINavigationControllerDelegate 자체로, 내 으로, 나는 그자,리, i in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in의 한다.UINavigationControllerDelegate 애니메이션 를 반환할 수 있습니다 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★,NavigationControllerAnimation이 커스텀 애니메이션 컨트롤러는 스톡 애니메이션을 대신합니다.

가 왜 이 NavigationControllerAnimationinitializer를 .이렇게 하는 이유는NavigationControllerAnimation> 님의 UIViewControllerAnimatedTransitioning프로토콜이 무엇인지 알고 있습니다(예: '푸시' 또는 '팝').이것은 내가 어떤 애니메이션을 해야 하는지 알아내는 데 도움이 된다.대부분의 경우 작업에 따라 다른 애니메이션을 수행하려고 합니다.

츠키노 두 필요한 해 보세요.UIViewControllerAnimatedTransitioning원하는 대로 프로토콜 및 애니메이션을 수행할 수 있습니다.

class NavigationControllerAnimation: NSObject, UIViewControllerAnimatedTransitioning {

    let operation: UINavigationControllerOperation

    init(operation: UINavigationControllerOperation) {
        self.operation = operation

        super.init()
    }

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

    public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) else { return }
        let containerView = transitionContext.containerView

        if operation == .push {
            // do your animation for push
        } else if operation == .pop {
            // do your animation for pop
        }
    }
}

각 조작 유형(즉, '푸시' 또는 '팝')에 따라 뷰 컨트롤러와 뷰 컨트롤러가 다르다는 것을 기억해야 합니다.푸시 조작 중에는 to view 컨트롤러가 푸시 대상입니다.팝 조작을 하고 있는 경우는, To View컨트롤러가 이행처이며, from view컨트롤러가 팝처입니다.

,,to는 뷰 컨트롤러의 해야 합니다.containerView를 참조해 주세요.

되면, 「 」에 전화할 가 있습니다.transitionContext.completeTransition(true)이행하는 Bool로로 합니다.completeTransition(didComplete: Bool)(애니메이션의 마지막에 이행이 완료되었는지 여부에 따라 달라집니다.

마지막으로(선택 사항 읽기) 작업 중인 전환 작업을 어떻게 수행했는지 확인할 수 있습니다.이 코드는 좀 더 해킹이 심해서 제가 아주 빨리 썼기 때문에 훌륭한 애니메이션 코드라고는 할 수 없지만 애니메이션 파트를 어떻게 해야 하는지 보여줍니다.

저는 UINavigation Controller가 일반적으로 사용하는 애니메이션을 모방하고 싶었지만 '다음 페이지 over top' 애니메이션 대신 새로운 뷰 컨트롤러가 나타나는 동시에 이전 뷰 컨트롤러의 1:1 애니메이션을 구현하고 싶었습니다.이것에 의해, 2개의 뷰 컨트롤러가 서로 핀 접속되어 있는 것처럼 보이는 효과가 있습니다.

조작의 , 시, 선, 음, 음, 음을 설정해야 .toViewController의 뷰을 x축의 containerView를 해, 에 애니메이션을 합니다.origin.x0으로★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」fromViewController its ' ' its its its its its its its its ' ' ' ' ' ' 'origin.x "Discreen" : "Displayed" (화면외부 링크:

toViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.size.width, dy: 0.0)

containerView.addSubview(toViewController.view)

UIView.animate(withDuration: transitionDuration(using: transitionContext),
               delay: 0,
               options: [ UIViewAnimationOptions.curveEaseOut ],
               animations: {
                toViewController.view.frame = containerView.bounds
                fromViewController.view.frame = containerView.bounds.offsetBy(dx: -containerView.frame.size.width, dy: 0)
},
               completion: { (finished) in
                transitionContext.completeTransition(true)
})

팝 연산은 기본적으로 반대입니다., 그럼 여기에다가 더해져요.toViewController의의 containerView를 " " " " " " "fromViewController오른쪽에서 애니메이션을 할 때toViewController★★★★★★★★★★★★★★★★★★:

containerView.addSubview(toViewController.view)

UIView.animate(withDuration: transitionDuration(using: transitionContext),
               delay: 0,
               options: [ UIViewAnimationOptions.curveEaseOut ],
               animations: {
                fromViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.width, dy: 0)
                toViewController.view.frame = containerView.bounds
},
               completion: { (finished) in
                transitionContext.completeTransition(true)
})

다음은 전체 swift 파일에 대한 요약입니다.

https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be

매우 간단합니다.

self.navigationController?.view.semanticContentAttribute = .forceRightToLeft

swift 4에 대해 업데이트된 답변을 기반으로 합니다.

★★★UIViewController

let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "yourViewController") as! yourViewController
    UIView.animate(withDuration: 0.75, animations: {() -> Void in
    UIView.setAnimationCurve(.easeInOut)
    self.navigationController?.pushViewController(terms, animated: true)
    UIView.setAnimationTransition(.flipFromRight, for: (self.navigationController?.view)!, cache: false)
})

팝의 경우

UIView.animate(withDuration: 0.75, animations: {() -> Void in
    UIView.setAnimationCurve(.easeInOut)
    UIView.setAnimationTransition(.flipFromLeft, for: (self.navigationController?.view)!, cache: false)
})
navigationController?.popViewController(animated: false)

@Swift 4.2에서의 Luca Davanzo의 답변

public extension UINavigationController {

    /**
     Pop current view controller to previous view controller.

     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func pop(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.popViewController(animated: false)
    }

    /**
     Push a new view controller on the view controllers's stack.

     - parameter vc:       view controller to push.
     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func push(viewController vc: UIViewController, transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.pushViewController(vc, animated: false)
    }

    private func addTransition(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        transition.type = type
        self.view.layer.add(transition, forKey: nil)
    }

}

UINavigation ControllerDelegate와 UIViewControllerAnimated가 있습니다.그곳으로 이행하면, 원하는 대로 애니메이션을 변경할 수 있습니다.

예를 들어 VC용 수직 팝 애니메이션입니다.

@objc class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning {

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
    return 0.5
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let containerView = transitionContext.containerView()
    let bounds = UIScreen.mainScreen().bounds
    containerView!.insertSubview(toViewController.view, belowSubview: fromViewController.view)
    toViewController.view.alpha = 0.5

    let finalFrameForVC = fromViewController.view.frame

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        fromViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.height)
        toViewController.view.alpha = 1.0
        }, completion: {
            finished in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    })
}

}

그리고 나서.

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    if operation == .Pop {
        return PopAnimator()
    }
    return nil;
}

유용한 튜토리얼 https://www.objc.io/issues/5-ios7/view-controller-transitions/

Swift에서도 같은 일을 하고 있습니다.

푸시용:

    UIView.animateWithDuration(0.75, animations: { () -> Void in
        UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
        self.navigationController!.pushViewController(nextView, animated: false)
        UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromRight, forView: self.navigationController!.view!, cache: false)
    })

팝의 경우:

저는 실제로 위의 답변과 조금 다르게 했습니다만, Swift 개발은 처음이라 옳지 않을 수도 있습니다.을 했다viewWillDisappear:animated:팝 했습니다.

    UIView.animateWithDuration(0.75, animations: { () -> Void in
        UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
        UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: self.navigationController!.view, cache: false)
    })

    super.viewWillDisappear(animated)

해서 '어울리지 않다'를 할 수 되었습니다.UIView.transition해 주세요.animated:falsepop, push, stack replace를 선택합니다.

if let nav = self.navigationController
{
    UIView.transition(with:nav.view, duration:0.3, options:.transitionCrossDissolve, animations: {
        _ = nav.popViewController(animated:false)
    }, completion:nil)
}

저도 최근에 비슷한 걸 하려고 했어요.UINavigation Controller의 슬라이딩 애니메이션은 싫지만, UIView가 제공하는 컬 같은 애니메이션은 하고 싶지 않았습니다.밀거나 터트릴 때 화면 사이를 크로스페이드 하고 싶었어요.

여기서의 문제는 뷰가 말 그대로 뷰를 삭제하거나 현재 뷰 위에 하나를 띄우는 것이므로 페이드 기능이 작동하지 않는다는 것입니다.제가 찾은 솔루션은 새로운 뷰를 가져와 UIView Controller 스택의 현재 상위 뷰에 서브 뷰로 추가하는 것이었습니다.알파 0을 더하고 크로스페이드 합니다.애니메이션 시퀀스가 끝나면 애니메이션을 하지 않고 보기를 스택에 푸시합니다.그런 다음 이전 topView로 돌아가서 변경한 내용을 정리합니다.

그것보다 조금 더 복잡해요. 왜냐하면 당신은 내비게이션을 가지고 있기 때문이죠.이행을 올바르게 표시하기 위해 조정해야 하는 항목.또, 회전을 실시하는 경우는, 뷰가 서브 뷰로 추가되어 화면에 올바르게 표시되도록, 프레임 사이즈를 조정할 필요가 있습니다.여기 제가 사용한 코드가 있습니다.UINavigation Controller를 하위 분류하여 푸시 메서드와 팝 메서드를 오버로드했습니다.

-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
      UIViewController *currentViewController = [self.viewControllers lastObject];
      //if we don't have a current controller, we just do a normal push
      if(currentViewController == nil)
      {
         [super pushViewController:viewController animated:animated];
         return;
      }
      //if no animation was requested, we can skip the cross fade
      if(!animation)
      {
         [super pushViewController:viewController animated:NO];
         return;
      }
      //start the cross fade.  This is a tricky thing.  We basically add the new view
//as a subview of the current view, and do a cross fade through alpha values.
//then we push the new view on the stack without animating it, so it seemlessly is there.
//Finally we remove the new view that was added as a subview to the current view.

viewController.view.alpha = 0.0;
//we need to hold onto this value, we'll be releasing it later
    NSString *title = [currentViewController.title retain];

//add the view as a subview of the current view
[currentViewController.view addSubview:viewController.view];
[currentViewController.view bringSubviewToFront:viewController.view];
UIBarButtonItem *rButtonItem = currentViewController.navigationItem.rightBarButtonItem;
UIBarButtonItem *lButtonItem = currentViewController.navigationItem.leftBarButtonItem;

NSArray *array = nil;

//if we have a right bar button, we need to add it to the array, if not, we will crash when we try and assign it
//so leave it out of the array we are creating to pass as the context.  I always have a left bar button, so I'm not checking to see if it is nil. Its a little sloppy, but you may want to be checking for the left BarButtonItem as well.
if(rButtonItem != nil)
    array = [[NSArray alloc] initWithObjects:currentViewController,viewController,title,lButtonItem,rButtonItem,nil];
else {
    array = [[NSArray alloc] initWithObjects:currentViewController,viewController,title,lButtonItem,nil];
}

//remove the right bar button for our transition
[currentViewController.navigationItem setRightBarButtonItem:nil animated:YES];
//remove the left bar button and create a backbarbutton looking item
//[currentViewController.navigationItem setLeftBarButtonItem:nil animated:NO];

//set the back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:title style:kButtonStyle target:self action:@selector(goBack)];
[currentViewController.navigationItem setLeftBarButtonItem:backButton animated:YES];
[viewController.navigationItem setLeftBarButtonItem:backButton animated:NO];
[backButton release];

[currentViewController setTitle:viewController.title];

[UIView beginAnimations:@"push view" context:array];
[UIView setAnimationDidStopSelector:@selector(animationForCrossFadePushDidStop:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.80];
[viewController.view setAlpha: 1.0];
[UIView commitAnimations];
}

-(void)animationForCrossFadePushDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{

UIViewController *c = [(NSArray*)context objectAtIndex:0];
UIViewController *n = [(NSArray*)context objectAtIndex:1];
NSString *title     = [(NSArray *)context objectAtIndex:2];
UIBarButtonItem *l = [(NSArray *)context objectAtIndex:3];
UIBarButtonItem *r = nil;
//not all views have a right bar button, if we look for it and it isn't in the context,
//we'll crash out and not complete the method, but the program won't crash.
//So, we need to check if it is there and skip it if it isn't.
if([(NSArray *)context count] == 5)
    r = [(NSArray *)context objectAtIndex:4];

//Take the new view away from being a subview of the current view so when we go back to it
//it won't be there anymore.
[[[c.view subviews] lastObject] removeFromSuperview];
[c setTitle:title];
[title release];
//set the search button
[c.navigationItem setLeftBarButtonItem:l animated:NO];
//set the next button
if(r != nil)
    [c.navigationItem setRightBarButtonItem:r animated:NO];


[super pushViewController:n animated:NO];

 }

코드에 기재되어 있는 바와 같이 왼쪽 바버튼 아이템은 항상 있기 때문에 애니메이션 대리자의 컨텍스트로 전달되는 어레이에 넣기 전에 제로 여부를 확인하지 않습니다.이렇게 하면 체크하는 것이 좋을지도 모릅니다.

제가 발견한 문제는 위임 방식으로 크래시해도 프로그램이 크래시되지 않는다는 것입니다.대리인이 완료하지 못하도록 할 뿐 아무런 경고도 받지 않습니다.
그래서 제가 그 대리인 루틴에서 청소를 하고 있었기 때문에 청소가 끝나지 않았기 때문에 이상한 시각적 행동을 일으켰습니다.

내가 만든 뒤로 버튼은 "GoBack" 메서드를 호출하고, 이 메서드는 팝 루틴을 호출합니다.

-(void)goBack
{ 
     [self popViewControllerAnimated:YES];
}

그리고 여기 제 팝 루틴이 있습니다.

-(UIViewController *)popViewControllerAnimated:(BOOL)animated
{
    //get the count for the number of viewControllers on the stack
int viewCount = [[self viewControllers] count];
//get the top view controller on the stack
UIViewController *topViewController = [self.viewControllers objectAtIndex:viewCount - 1];
//get the next viewController after the top one (this will be the new top one)
UIViewController *newTopViewController = [self.viewControllers objectAtIndex:viewCount - 2];

//if no animation was requested, we can skip the cross fade
if(!animated)
{
    [super popViewControllerAnimated:NO];
            return topViewController;
}



//start of the cross fade pop.  A bit tricky.  We need to add the new top controller
//as a subview of the curent view controler with an alpha of 0.  We then do a cross fade.
//After that we pop the view controller off the stack without animating it.
//Then the cleanup happens: if the view that was popped is not released, then we
//need to remove the subview we added and change some titles back.
newTopViewController.view.alpha = 0.0;
[topViewController.view addSubview:newTopViewController.view];
[topViewController.view bringSubviewToFront:newTopViewController.view];
NSString *title = [topViewController.title retain];
UIBarButtonItem *lButtonItem = topViewController.navigationItem.leftBarButtonItem;
UIBarButtonItem *rButtonItem = topViewController.navigationItem.rightBarButtonItem;

//set the new buttons on top of the current controller from the new top controller
if(newTopViewController.navigationItem.leftBarButtonItem != nil)
{
    [topViewController.navigationItem setLeftBarButtonItem:newTopViewController.navigationItem.leftBarButtonItem animated:YES];
}
if(newTopViewController.navigationItem.rightBarButtonItem != nil)
{
    [topViewController.navigationItem setRightBarButtonItem:newTopViewController.navigationItem.rightBarButtonItem animated:YES];
}

[topViewController setTitle:newTopViewController.title];
//[topViewController.navigationItem.leftBarButtonItem setTitle:newTopViewController.navigationItem.leftBarButtonItem.title];

NSArray *array = nil;
if(rButtonItem != nil)
    array = [[NSArray alloc] initWithObjects:topViewController,title,lButtonItem,rButtonItem,nil];
else {
    array = [[NSArray alloc] initWithObjects:topViewController,title,lButtonItem,nil];
}


[UIView beginAnimations:@"pop view" context:array];
[UIView setAnimationDidStopSelector:@selector(animationForCrossFadePopDidStop:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.80];
[newTopViewController.view setAlpha: 1.0];
[UIView commitAnimations];
return topViewController;

 }

 -(void)animationForCrossFadePopDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
 {

UIViewController *c = [(NSArray *)context objectAtIndex:0];
//UIViewController *n = [(NSArray *)context objectAtIndex:1];
NSString *title = [(NSArray *)context objectAtIndex:1];
UIBarButtonItem *l = [(NSArray *)context objectAtIndex:2];
UIBarButtonItem *r = nil;



//Not all views have a right bar button.  If we look for one that isn't there
// we'll crash out and not complete this method, but the program will continue.
//So we need to check if it is therea nd skip it if it isn't.
if([(NSArray *)context count] == 4)
    r = [(NSArray *)context objectAtIndex:3];

//pop the current view from the stack without animation
[super popViewControllerAnimated:NO];

//if what was the current veiw controller is not nil, then lets correct the changes
//we made to it.
if(c != nil)
{
    //remove the subview we added for the transition
    [[c.view.subviews lastObject] removeFromSuperview];
    //reset the title we changed
    c.title = title;
    [title release];
    //replace the left bar button that we changed
    [c.navigationItem setLeftBarButtonItem:l animated:NO];
    //if we were passed a right bar button item, replace that one as well
    if(r != nil)
        [c.navigationItem setRightBarButtonItem:r animated:NO];
    else {
        [c.navigationItem setRightBarButtonItem:nil animated:NO];
    }


 }
}

거의 다 됐습니다.로테이션을 구현하려면 추가 코드가 필요합니다.서브뷰로 추가하는 뷰의 프레임 크기를 설정한 후 표시해야 합니다.설정하지 않으면 방향은 가로 방향이지만 이전 뷰를 마지막으로 본 것은 세로 방향입니다.서브 뷰로 추가하고 페이드 인하면 세로 표시로 표시됩니다.애니메이션 없이 팝업을 하면 같은 뷰지만 스택에 있는 뷰가 가로로 표시됩니다.모든 게 좀 펑키해보여.로테이션의 실장은 사람마다 조금씩 다르기 때문에, 거기에 대한 코드를 여기에 넣지 않았습니다.

도움이 됐으면 좋겠어요.이런 걸 찾아 헤맸지만 아무것도 못 찾았어요.이것이 완벽한 답은 아니라고 생각합니다만, 현시점에서는 매우 효과가 있습니다.

iJordan의 답변을 참고하여 UINavigation Controller에 카테고리를 만들어 앱 전체에 사용하는 것이 아니라 애니메이션 코드를 복사/붙여넣는 것이 어떻습니까?

UINavigation Controller+Animation.h

@interface UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController*) controller;

- (void) popViewControllerWithFlip;

@end

UINavigation Controller+Animation.m

@implementation UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController *) controller
{
    [UIView animateWithDuration:0.50
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [self pushViewController:controller animated:NO];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];
}

- (void) popViewControllerWithFlip
{
    [UIView animateWithDuration:0.5
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];

    [self popViewControllerAnimated:NO];
}

@end

그런 다음 UINavigation Controller+Animation.h 파일을 Import하여 정상적으로 호출합니다.

[self.navigationController pushViewControllerWithFlip:[[NewViewController alloc] init]];

[self.navigationController popViewControllerWithFlip];

ADTransition Controller를 보세요.ADTransition Controller는 UINavigation Controller를 커스텀 전환 애니메이션으로 대체한 것입니다(API는 UINavigation Controller의 API와 일치합니다).

Swipe, Fade, Cube, Carrousel, Zoom 등과 같은 다양한 사전 정의된 애니메이션을 푸시 및 팝 작업에 사용할 수 있습니다.

여기 있는 모든 답변은 훌륭하고 대부분 잘 작동하지만, 같은 효과를 얻을 수 있는 조금 더 간단한 방법이 있습니다.

푸시용:

  NextViewController *nextViewController = [[NextViewController alloc] init];

  // Shift the view to take the status bar into account 
  CGRect frame = nextViewController.view.frame;
  frame.origin.y -= 20;
  frame.size.height += 20;
  nextViewController.view.frame = frame;

  [UIView transitionFromView:self.navigationController.topViewController.view toView:nextViewController.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished) {
    [self.navigationController pushViewController:nextViewController animated:NO];
  }];

팝의 경우:

  int numViewControllers = self.navigationController.viewControllers.count;
  UIView *nextView = [[self.navigationController.viewControllers objectAtIndex:numViewControllers - 2] view];

  [UIView transitionFromView:self.navigationController.topViewController.view toView:nextView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
    [self.navigationController popViewControllerAnimated:NO];
  }];}

트랜지션 애니메이션을 공개적으로 변경할 수 있는 방법이 없습니다.

"뒤로" 버튼이 필요하지 않은 경우 "아래에서 밀어넣기" / "플립" / "페이드" / (33.2)" 페이지 컬을 전환하기 위해 모드컨트롤러사용해야 합니다.


프라이빗 사이드에서 방법은-pushViewController:animated:되어 있지 않은 메서드를 합니다.-pushViewController:transition:forceImmediate:에서 오른쪽으로의 플립 " "를 할 수

[navCtrler pushViewController:ctrler transition:10 forceImmediate:NO];

그러나 이러한 방식으로 "팝" 전환을 변경할 수는 없습니다.

훨씬 적은 수의 코드로 이 문제를 해결할 수 있는 방법은 이 질문에 대한 답변을 참조하십시오.이 방법을 사용하면 새 뷰 컨트롤러의 유사 "푸시"를 원하는 방식으로 애니메이션화할 수 있으며 애니메이션이 완료되면 표준 푸시 방법을 사용한 것처럼 내비게이션 컨트롤러를 설정할 수 있습니다.이 예에서는 왼쪽 또는 오른쪽에서 슬라이드 인을 애니메이션으로 만들 수 있습니다.편의를 위해 여기에 코드가 반복되었습니다.

-(void) showVC:(UIViewController *) nextVC rightToLeft:(BOOL) rightToLeft {
    [self addChildViewController:neighbor];
    CGRect offscreenFrame = self.view.frame;
    if(rightToLeft) {
        offscreenFrame.origin.x = offscreenFrame.size.width * -1.0;
    } else if(direction == MyClimbDirectionRight) {
        offscreenFrame.origin.x = offscreenFrame.size.width;
    }
    [[neighbor view] setFrame:offscreenFrame];
    [self.view addSubview:[neighbor view]];
    [neighbor didMoveToParentViewController:self];
    [UIView animateWithDuration:0.5 animations:^{
        [[neighbor view] setFrame:self.view.frame];
    } completion:^(BOOL finished){
        [neighbor willMoveToParentViewController:nil];
        [neighbor.view removeFromSuperview];
        [neighbor removeFromParentViewController];
        [[self navigationController] pushViewController:neighbor animated:NO];
        NSMutableArray *newStack = [[[self navigationController] viewControllers] mutableCopy];
        [newStack removeObjectAtIndex:1]; //self, just below top
        [[self navigationController] setViewControllers:newStack];
    }];
}

샘플 앱에서 이 변형을 확인하십시오.https://github.com/mpospese/MPFoldTransition/

#pragma mark - UINavigationController(MPFoldTransition)

@implementation UINavigationController(MPFoldTransition)

//- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
- (void)pushViewController:(UIViewController *)viewController foldStyle:(MPFoldStyle)style
{
    [MPFoldTransition transitionFromViewController:[self visibleViewController] 
                                  toViewController:viewController 
                                          duration:[MPFoldTransition defaultDuration]  
                                             style:style 
                                        completion:^(BOOL finished) {
                                            [self pushViewController:viewController animated:NO];
                                        }
     ];
}

- (UIViewController *)popViewControllerWithFoldStyle:(MPFoldStyle)style
{
    UIViewController *toController = [[self viewControllers] objectAtIndex:[[self viewControllers] count] - 2];

    [MPFoldTransition transitionFromViewController:[self visibleViewController] 
                                  toViewController:toController 
                                          duration:[MPFoldTransition defaultDuration] 
                                             style:style
                                        completion:^(BOOL finished) {
                                            [self popViewControllerAnimated:NO];
                                        }
     ];

    return toController;
}

사용방법:

ViewController *viewController = [[ViewController alloc] init];

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.navigationBarHidden = YES;

[self presentViewController:navController animated:YES completion: nil];
[viewController release];
[navController release];

을 사용법 가지 이 .viewControllers이치노 myclassclassclass class my my my 。UINavigationController이치

FlippingNavigationController.h

@interface FlippingNavigationController : UINavigationController

@end

FlickingNavigationController.m:

#import "FlippingNavigationController.h"

#define FLIP_DURATION 0.5

@implementation FlippingNavigationController

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [UIView transitionWithView:self.view
                      duration:animated?FLIP_DURATION:0
                       options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionFlipFromRight
                    animations:^{ [super pushViewController:viewController
                                                   animated:NO]; }
                    completion:nil];
}

- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
    return [[self popToViewController:[self.viewControllers[self.viewControllers.count - 2]]
                             animated:animated] lastObject];
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
{
    return [self popToViewController:[self.viewControllers firstObject]
                            animated:animated];
}

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    __block NSArray* viewControllers = nil;

    [UIView transitionWithView:self.view
                      duration:animated?FLIP_DURATION:0
                       options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionFlipFromLeft
                    animations:^{ viewControllers = [super popToViewController:viewController animated:NO]; }
                    completion:nil];

    return viewControllers;
}

@end

이 실타래가 오래됐다는 건 알지만, 의견을 말해야겠다고 생각했어요.커스텀 애니메이션을 만들 필요는 없습니다.간단한(아마도 해킹할 수 있는) 방법이 있습니다.푸시를 사용하는 대신 새 내비게이션 컨트롤러를 만들고 새 뷰 컨트롤러를 해당 내비게이션 컨트롤러의 루트 뷰 컨트롤러로 만든 다음 원래 내비게이션 컨트롤러에서 내비게이션 컨트롤러를 표시합니다.Present는 다양한 스타일로 쉽게 커스터마이즈할 수 있으며 커스텀 애니메이션을 만들 필요가 없습니다.

예를 들어 다음과 같습니다.

UIViewcontroller viewControllerYouWantToPush = UIViewController()
UINavigationController newNavController = UINavigationController(root: viewControllerYouWantToView)
newNavController.navBarHidden = YES;
self.navigationController.present(newNavController)

그리고 프레젠테이션 스타일을 원하는 대로 변경할 수 있습니다.

내 목적에 맞는 약간 반복적인 방법을 찾았습니다.일반 팝 애니메이션을 차단하고 애니메이션이 아닌 팝 메시지를 대체하기 위해 사용하는 BOOL 인스턴스 변수가 있습니다.변수는 처음에 NO로 설정됩니다.뒤로 버튼을 누르면 위임 메서드는 이를 YES로 설정하고 새로운 비애니메이션 팝 메시지를 탐색 모음으로 보냅니다. 그러면 변수가 YES로 설정된 상태에서 동일한 위임 메서드를 다시 호출합니다.변수가 YES로 설정된 경우 위임 메서드는 변수를 NO로 설정하고 애니메이션이 아닌 팝이 발생할 수 있도록 YES를 반환합니다.두 번째 딜러 콜이 반환된 후 첫 번째 딜러 콜이 반환되고 NO가 반환되며 원래 애니메이션 팝이 차단됩니다.사실 말처럼 그렇게 지저분하진 않아요.내 팝(My should pop항목 방법은 다음과 같습니다.

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item 
{
    if ([[navigationBar items] indexOfObject:item] == 1) 
    {
        [expandedStack restack];    
    }

    if (!progPop) 
    {
        progPop = YES;
        [navBar popNavigationItemAnimated:NO];
        return NO;
    }
    else 
    {
        progPop = NO;
        return YES;
    }
}

저는 좋아요.

언급URL : https://stackoverflow.com/questions/2215672/how-to-change-the-push-and-pop-animations-in-a-navigation-based-app

반응형