Как выполнить pushViewController в стеке UINavigationController с жесткой ставкой? [Дубликат]

Он называется свободным интерфейсом '. Просто измените тип возвращаемого значения и return this;, чтобы вы могли привязать методы:

public MyClass ifExist(Consumer consumer) {
    if (exist()) {
        consumer.accept(this);
    }
    return this;
}

public MyClass ifNotExist(Consumer consumer) {
    if (!exist()) {
        consumer.accept(this);
    }
    return this;
}

Вы могли бы получить немного более интересный и вернуть промежуточный тип:

interface Else
{
    public void otherwise(Consumer consumer); // 'else' is a keyword
}

class DefaultElse implements Else
{
    private final T item;

    DefaultElse(final T item) { this.item = item; }

    public void otherwise(Consumer consumer)
    {
        consumer.accept(item);
    }
}

class NoopElse implements Else
{
    public void otherwise(Consumer consumer) { }
}

public Else ifExist(Consumer consumer) {
    if (exist()) {
        consumer.accept(this);
        return new NoopElse<>();
    }
    return new DefaultElse<>(this);
}

Образец использование:

element.ifExist(el -> {
    //do something
})
.otherwise(el -> {
    //do something else
});

69
задан AVAVT 7 December 2015 в 15:17
поделиться

4 ответа

Чтобы выполнить пользовательский переход с навигационным контроллером (UINavigationController), вы должны:

  • Определить контроллер вида для соответствия протоколу UINavigationControllerDelegate. Например, вы можете иметь расширение частного класса в файле .m контроллера вашего вида, который указывает соответствие этому протоколу:
    @interface ViewController () <UINavigationControllerDelegate>
    
    @end
    
  • Убедитесь, что вы фактически указали свой контроллер представления в качестве делегата вашего диспетчера навигации:
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.navigationController.delegate = self;
    }
    
  • Внесите animationControllerForOperation в контроллер вашего вида:
    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController*)fromVC
                                                     toViewController:(UIViewController*)toVC
    {
        if (operation == UINavigationControllerOperationPush)
            return [[PushAnimator alloc] init];
    
        if (operation == UINavigationControllerOperationPop)
            return [[PopAnimator alloc] init];
    
        return nil;
    }
    
  • Внедрите аниматоры для анимации push и pop, например:
    @interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @implementation PushAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
        [[transitionContext containerView] addSubview:toViewController.view];
    
        toViewController.view.alpha = 0.0;
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            toViewController.view.alpha = 1.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    
    @implementation PopAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
        [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromViewController.view.alpha = 0.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    
    Это приводит к постепенному переходу, но вы должны чувствовать
  • Если вы хотите обрабатывать интерактивные жесты (например, что-то вроде собственного прокрутки слева направо, чтобы поп), вы должны реализовать контроллер взаимодействия: определить свойство для контроллера взаимодействия (объект, который соответствует UIViewControllerInteractiveTransitioning):
    @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;
    
    Этот UIPercentDrivenInteractiveTransition является хорошим объектом, который делает тяжелый подъем обновления вашей пользовательской анимации в зависимости от того, насколько завершен жест. Добавьте распознаватель жестов к вашему виду. Здесь я просто внедряю левый распознаватель жестов, чтобы имитировать поп:
    UIScreenEdgePanGestureRecognizer *edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFromLeftEdge:)];
    edge.edges = UIRectEdgeLeft;
    [view addGestureRecognizer:edge];
    
    Внедрить обработчик распознавателя жестов:
    /** Handle swipe from left edge
     *
     * This is the "action" selector that is called when a left screen edge gesture recognizer starts.
     *
     * This will instantiate a UIPercentDrivenInteractiveTransition when the gesture starts,
     * update it as the gesture is "changed", and will finish and release it when the gesture
     * ends.
     *
     * @param   gesture       The screen edge pan gesture recognizer.
     */
    
    - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture {
        CGPoint translate = [gesture translationInView:gesture.view];
        CGFloat percent   = translate.x / gesture.view.bounds.size.width;
    
        if (gesture.state == UIGestureRecognizerStateBegan) {
            self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];
            [self popViewControllerAnimated:TRUE];
        } else if (gesture.state == UIGestureRecognizerStateChanged) {
            [self.interactionController updateInteractiveTransition:percent];
        } else if (gesture.state == UIGestureRecognizerStateEnded) {
            CGPoint velocity = [gesture velocityInView:gesture.view];
            if (percent > 0.5 || velocity.x > 0) {
                [self.interactionController finishInteractiveTransition];
            } else {
                [self.interactionController cancelInteractiveTransition];
            }
            self.interactionController = nil;
        }
    }
    
    В вашем делете контроллера навигации вы также должны реализовать interactionControllerForAnimationController метод делегата
    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                             interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
        return self.interactionController;
    }
    

Если вы google "UINavigationController настраиваемый переход учебник", и вы получите много хитов. Или см. видеоролики пользовательских переходов WWDC 2013 .

183
ответ дан Rob 28 August 2018 в 07:42
поделиться

Вы можете добавить следующий код до addSubview

  toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

С другого вопроса custom-transition-for-push-animation-with-navigationcontroller-on-ios-9

Из документации Apple для finalFrameForViewController:

Возвращает прямоугольник конечного кадра для указанного представления контроллера представления.

Прямоугольник, возвращаемый этим метод представляет размер соответствующего представления в конце перехода. Для представления, которое рассматривается во время презентации, значение, возвращаемое этим методом, может быть CGRectZero, но оно также может быть допустимым прямоугольником рамки.

13
ответ дан Community 28 August 2018 в 07:42
поделиться

Использование Rob & amp; Q i - идеальные ответы, вот упрощенный код Swift, использующий ту же самую затухающую анимацию для .push и .pop:

extension YourViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationControllerOperation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

        //INFO: use UINavigationControllerOperation.push or UINavigationControllerOperation.pop to detect the 'direction' of the navigation

        class FadeAnimation: NSObject, UIViewControllerAnimatedTransitioning {
            func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
                return 0.5
            }

            func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
                let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
                if let vc = toViewController {
                    transitionContext.finalFrame(for: vc)
                    transitionContext.containerView.addSubview(vc.view)
                    vc.view.alpha = 0.0
                    UIView.animate(withDuration: self.transitionDuration(using: transitionContext),
                    animations: {
                        vc.view.alpha = 1.0
                    },
                    completion: { finished in
                        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                    })
                } else {
                    NSLog("Oops! Something went wrong! 'ToView' controller is nill")
                }
            }
        }

        return FadeAnimation()
    }
}

Не забудьте указать делегата в методе viewDidLoad () в вашем представлении ViewView: g1]

override func viewDidLoad() {
    //...
    self.navigationController?.delegate = self
    //...
}
3
ответ дан Edmund Elmer 28 August 2018 в 07:42
поделиться

Он работает как быстрыми 3, так и 4

    @IBAction func NextView(_ sender: UIButton) {
        let newVC = self.storyboard?.instantiateViewControllerWithIdentifier(withIdentifier: "NewVC") as! NewViewController

                let transition = CATransition()
                transition.duration = 0.5
                transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
                transition.type = kCATransitionPush
                transition.subtype = kCAGravityLeft
    //instead "kCAGravityLeft" try with different transition subtypes

        self.navigationController?.view.layer.add(transition, forKey: kCATransition)
        self.navigationController?.pushViewController(newVC, animated: false)

            }
2
ответ дан Sai kumar Reddy 28 August 2018 в 07:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: