実現したいこと
https://github.com/aivars/SlideOverTutorial
を参考にハーフモーダル遷移を実装しました。
このハーフモーダル画面にtextFieldを配置し、キーボードの高さに応じてキーボードの高さも高くすることによって、端末が変わっても、textFieldが隠れないように実装したいです。
発生している問題・エラーメッセージ
keyboardWillShow(notification: NSNotification)でキーボードの高さを取得してから、どうやってハーフモーダルの高さを取得すればいいのかが解りません。
現状のコードだと、viewが大きく上に持ち上がった状態になってしまいます。
なかなか前に進めなくなってしまい、質問させて頂きました。
該当のソースコード
以下コード全文です。
swift.ViewController
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } @objc func showMiracle() { let slideVC = OverlayView() slideVC.modalPresentationStyle = .custom slideVC.transitioningDelegate = self self.present(slideVC, animated: true, completion: nil) } @IBAction func onButton(_ sender: Any) { showMiracle() } } extension ViewController: UIViewControllerTransitioningDelegate { func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { PresentationController(presentedViewController: presented, presenting: presenting) } }
swift.PresentationController
import UIKit 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.37), size: CGSize(width: self.containerView!.frame.width, height: self.containerView!.frame.height * 0.63)) } 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 } }
swift.OverlayView
import UIKit class OverlayView: UIViewController { @IBOutlet weak var textField: UITextField! var hasSetPointOrigin = false var pointOrigin: CGPoint? override func viewDidLoad() { super.viewDidLoad() let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognizerAction)) view.addGestureRecognizer(panGesture) textField.keyboardType = .namePhonePad textField.delegate = self textField.becomeFirstResponder() NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) } @objc func keyboardWillShow(notification: NSNotification) { if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { let suggestionHeight = self.view.frame.origin.y + keyboardSize.height self.view.frame.origin.y -= suggestionHeight } } @objc func keyboardWillHide() { if self.view.frame.origin.y != 0 { self.view.frame.origin.y = 0 } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) } override func viewDidLayoutSubviews() { if !hasSetPointOrigin { hasSetPointOrigin = true pointOrigin = self.view.frame.origin } } @objc func panGestureRecognizerAction(sender: UIPanGestureRecognizer) { let translation = sender.translation(in: view) // Not allowing the user to drag the view upward guard translation.y >= 0 else { return } // setting x as 0 because we don't want users to move the frame side ways!! Only want straight up or down view.frame.origin = CGPoint(x: 0, y: self.pointOrigin!.y + translation.y) if sender.state == .ended { let dragVelocity = sender.velocity(in: view) if dragVelocity.y >= 1300 { self.dismiss(animated: true, completion: nil) } else { // Set back to original position of the view controller UIView.animate(withDuration: 0.3) { self.view.frame.origin = self.pointOrigin ?? CGPoint(x: 0, y: 400) } } } } } extension OverlayView: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } }
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
まだ回答がついていません
会員登録して回答してみよう