VesselWheel

Half Modal로 기본 뷰 위에 다른 뷰 올리기(feat. UISheetPresentationController) 본문

Xcode Study

Half Modal로 기본 뷰 위에 다른 뷰 올리기(feat. UISheetPresentationController)

JasonYang 2024. 1. 22. 00:14

UISheetPresentationController을 이용해서 하프모달을 구현해보자.

공식문서 

https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller

 

UISheetPresentationController | Apple Developer Documentation

A presentation controller that manages the appearance and behavior of a sheet.

developer.apple.com

 

맵뷰에서 킥보드 등록을 위해 [대여하기]버튼을 탭하면 킥보드의 대여상태를 UI로 구현하기 위해 여러가지 방법이 있다.

그 중에서 [대여하기] 버튼을 탭하면 Register로 뷰를 전환할 때 UISheetPresentationController을 이용해서 뷰 전환을 일으킬 때 하프모달로 같은 화면에서 기능을 구현하면 기존에 보고 있던 지도의 시각이 변하지 않으면서 사용자는 정보를 입력할 수 있다. 

MapView 위에 하프모달로 구현된 RegisterView

매소드화한 하프모달 코드 

import Foundation

// In a subclass of UIViewController, customize and present the sheet.
extension MapViewController {
    func showMyViewControllerInACustomizedSheet() {
        let viewControllerToPresent = RegisterViewController() // 여기를 실제 표시하고자 하는 뷰 컨트롤러로 변경
        if let sheet = viewControllerToPresent.sheetPresentationController {
            sheet.detents = [.medium()] // 모달의 높이를 중간.medium과 크게.large로 설정합니다.
            sheet.largestUndimmedDetentIdentifier = .medium // 최대 확장 시 어둡게 표시되지 않도록 설정
            sheet.prefersScrollingExpandsWhenScrolledToEdge = false // 모달 내부 스크롤 시 확장되지 않도록 설정
            sheet.prefersEdgeAttachedInCompactHeight = true // 컴팩트 높이에서 모달이 화면 가장자리에 붙도록 설정
            sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true // 모달의 너비가 preferredContentSize를 따르도록 설정
        }
        present(viewControllerToPresent, animated: true, completion: nil)
    }
}

 

MapView에서 사용되는 하프모달 매소드 showMyViewControllerInACustomizedSheet()

   @IBAction func tappedButtonBorrow(_ sender: UIButton) {
        if let myKickboardID = selectedKickboardID, let kickboardToBorrow = kickboardItems.first(where: { $0.id == selectedKickboardID }) {
            if kickboardToBorrow.subtitle == "대여가능" {
                print("킥보드 대여하기가 신청되었습니다.")
                showMyViewControllerInACustomizedSheet()
                DispatchQueue.main.async {
                    self.buttonKickboard.backgroundColor = .green
                    self.buttonBicycle.backgroundColor = .white
                }
            } else {
                alertButton(in: self, title: "이미 대여 중인 킥보드입니다.", messgae: "대여를 원하신다면 '네'를 눌러주세요.")
            }
        } else if let myBicylceID = selectedBicycleID, let bicycleToBorrow = bicycleItems.first(where: {$0.id == selectedBicycleID}) {
            if bicycleToBorrow.subtitle == "대여가능" {
                print("자전거 대여하기가 신청되었습니다.")
                DispatchQueue.main.async {
                    self.buttonBicycle.backgroundColor = .green
                    self.buttonKickboard.backgroundColor = .white
                }
            } else {
                alertButton(in: self, title: "이미 대여 중인 자전거입니다.", messgae: "대여를 원하신다면 '네'를 눌러주세요.")
            }
        } else {
            let notSelectedMessage = "선택된 킥보드 또는 자전거가 없습니다."
            alertButton(in: self, title: notSelectedMessage, messgae: "대여를 원하신다면 '네'를 눌러주세요.")
        }
    }

showMyViewControllerInACustomizedSheet() 매소드가 IBAction 함수 tappedButtonBorrow에서 실행될 때 대여가능상태를 확인한 후 DispatchQueue.main.async 가 실행되기 전에 실행된다.