Как представить полумодальный контроллер представления поверх с пользовательскими переходами iOS 7

Как бы я мог представить контроллер "половинного обзора" поверх контроллера основного вида?

Требования: - Представьте второй контроллер вида, который скользит поверх контроллера основного вида. - Контроллер второго вида должен показывать только более половины контроллера основного вида - Контроллер основного вида должен оставаться видимым за контроллером второго вида (прозрачный фон, не показывать черный снизу) - Контроллер второго вида должен анимироваться с анимацией, аналогичной модальной вертикальной обложке, или Пользовательский переход iOS 7 - пользователь по-прежнему может взаимодействовать с кнопками на контроллере основного вида, когда контроллер второго вида активен (т. е. контроллер второго вида не охватывает весь контроллер основного вида). r ​​- Контроллер второго вида имеет собственную сложную логику (не может быть простой вид) - раскадровки, сегы, только iOS 7 - только iPhone, а не iPad.

Я попытался с модальным контроллером представления, но это не позволяет взаимодействие с главным контроллером представления. Может кто-нибудь привести пример того, как сделать это с помощью пользовательского перехода iOS7 или другим методом.

2 ответа

Решение

Один из способов сделать это - добавить "полумодальный" контроллер в качестве дочернего контроллера представления и анимировать его представление на месте. В этом примере я создал "полумодальный" контроллер в раскадровке с рамкой, равной половине высоты 4-дюймового экрана iPhone. Вы можете использовать более динамичные методы для учета различных размеров экрана, но это должно помочь вам начать.

@interface ViewController ()
@property (strong,nonatomic) UIViewController *modal;
@end

@implementation ViewController


- (IBAction)toggleHalfModal:(UIButton *)sender {
    if (self.childViewControllers.count == 0) {
        self.modal = [self.storyboard instantiateViewControllerWithIdentifier:@"HalfModal"];
        [self addChildViewController:self.modal];
        self.modal.view.frame = CGRectMake(0, 568, 320, 284);
        [self.view addSubview:self.modal.view];
        [UIView animateWithDuration:1 animations:^{
            self.modal.view.frame = CGRectMake(0, 284, 320, 284);;
        } completion:^(BOOL finished) {
            [self.modal didMoveToParentViewController:self];
        }];
    }else{
        [UIView animateWithDuration:1 animations:^{
            self.modal.view.frame = CGRectMake(0, 568, 320, 284);
        } completion:^(BOOL finished) {
            [self.modal.view removeFromSuperview];
            [self.modal removeFromParentViewController];
            self.modal = nil;
        }];
    }
}

Новый способ отображения контроллера на половине экрана — это контроллер собственного стиля ios.

Ниже фрагмент кода поможет вам для обеих версий

          controller.modalPresentationStyle = .pageSheet
    if #available(iOS 15.0, *) {

        if let sheet = controller.sheetPresentationController {
            sheet.detents = [.medium()]
        }
        
    } else {
        
        controller.modalPresentationStyle = .custom
        controller.transitioningDelegate = self
    }
    self.present(controller, animated: true, completion: nil)

// ПОМЕТКА: - UIViewControllerTransitioningDelegate

        extension CPPdfPreviewVC: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    PresentationController(presentedViewController: presented, presenting: presenting)
    }
}

и добавьте контроллер презентации, как указано

        class PresentationController: UIPresentationController {


  let blurEffectView: UIVisualEffectView!
  var tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
  
  override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
      let blurEffect = UIBlurEffect(style: .dark)
      blurEffectView = UIVisualEffectView(effect: blurEffect)
      super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
      tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissController))
      blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
      self.blurEffectView.isUserInteractionEnabled = true
      self.blurEffectView.addGestureRecognizer(tapGestureRecognizer)
  }
  
  override var frameOfPresentedViewInContainerView: CGRect {
      CGRect(origin: CGPoint(x: 0, y: self.containerView!.frame.height * 0.4),
             size: CGSize(width: self.containerView!.frame.width, height: self.containerView!.frame.height *
              0.6))
  }

  override func presentationTransitionWillBegin() {
      self.blurEffectView.alpha = 0
      self.containerView?.addSubview(blurEffectView)
      self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
          self.blurEffectView.alpha = 0.7
      }, completion: { (UIViewControllerTransitionCoordinatorContext) in })
  }
  
  override func dismissalTransitionWillBegin() {
      self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
          self.blurEffectView.alpha = 0
      }, completion: { (UIViewControllerTransitionCoordinatorContext) in
          self.blurEffectView.removeFromSuperview()
      })
  }
  
  override func containerViewWillLayoutSubviews() {
      super.containerViewWillLayoutSubviews()
    presentedView!.roundCorners([.topLeft, .topRight], radius: 22)
  }

  override func containerViewDidLayoutSubviews() {
      super.containerViewDidLayoutSubviews()
      presentedView?.frame = frameOfPresentedViewInContainerView
      blurEffectView.frame = containerView!.bounds
  }

  @objc func dismissController(){
      self.presentedViewController.dismiss(animated: true, completion: nil)
  }
}

extension UIView {
  func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
      let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners,
                              cornerRadii: CGSize(width: radius, height: radius))
      let mask = CAShapeLayer()
      mask.path = path.cgPath
      layer.mask = mask
  }
}
Другие вопросы по тегам