관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] UISheetPresentationController, Bottom Sheet, Sheet Drawer, 애플 지도에서 사용되는 뷰 본문

iOS 응용 (swift)

[iOS - swift] UISheetPresentationController, Bottom Sheet, Sheet Drawer, 애플 지도에서 사용되는 뷰

jake-kim 2021. 10. 21. 23:16

UISheetPresentationController

  • iOS 15+ 부터 제공
  • 내부적으로 UIViewController안에 프로퍼티가 존재하므로, UIViewController에서 바로 사용 가능

사용 방법

  • SheetPresentation에 담길 MyViewController 정의
class MyViewController: UIViewController {

    lazy var tableView: UITableView = {
        let view = UITableView()
        view.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        view.delegate = self
        view.dataSource = self

        return view
    }()

    var dataSource = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        title = "MyViewController"

        for i in 0...100 {
            dataSource.append("\(i)")
        }

        view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 30)
        ])

        setupSheet()
        addNavigationBarButtonItem()

    }

    private func setupSheet() {
		// TODO
    }

    private func addNavigationBarButtonItem() {
		// TODO
    }
}

extension MyViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = dataSource[indexPath.row]
        return cell
    }
}
  • setupSheet() 정의
    • 디폴트로, sheet를 아래로 당기면 dismiss되는데 이 기능을 막기위해서 `isModalInPresentation = true`로 설정
    • UIViewController는 내부적으로 sheetPresentationController 프로퍼티를 가지고 있으므로 그 값을 활용
    • 핵심: detents (멈춤쇠라는 의미) 설정
private func setupSheet() {
    /// 밑으로 내려도 dismiss되지 않는 옵션 값
    isModalInPresentation = true

    if let sheet = sheetPresentationController {
        /// 드래그를 멈추면 그 위치에 멈추는 지점: default는 large()
        sheet.detents = [.medium(), .large()]
        /// 초기화 드래그 위치
        sheet.selectedDetentIdentifier = .medium
        /// sheet아래에 위치하는 ViewController를 흐려지지 않게 하는 경계값 (medium 이상부터 흐려지도록 설정)
        sheet.largestUndimmedDetentIdentifier = .medium
        /// sheet로 present된 viewController내부를 scroll하면 sheet가 움직이지 않고 내부 컨텐츠를 스크롤되도록 설정
        sheet.prefersScrollingExpandsWhenScrolledToEdge = false
        /// grabber바 보이도록 설정
        sheet.prefersGrabberVisible = true
        /// corner 값 설정
//      sheet.preferredCornerRadius = 32.0
    }
}
  • addNavigationBarButtonItem() 정의
    • medium버튼과 large버튼을 만들고 그 버튼을 탭하면 각 위치로 이동하게끔 구현
    • `sheetPresentationController?.selecrtedDetentIdentifier`값 이용
private func addNavigationBarButtonItem() {
    let medium = UIBarButtonItem(title: "medium", primaryAction: .init(handler: { [weak self] _Arg in
        self?.sheetPresentationController?.animateChanges {
            self?.sheetPresentationController?.selectedDetentIdentifier = .medium
        }
    }))
    navigationItem.leftBarButtonItem = medium

    let large = UIBarButtonItem(title: "large", primaryAction: .init(handler: { [weak self] _Arg in
        self?.sheetPresentationController?.animateChanges {
            self?.sheetPresentationController?.selectedDetentIdentifier = .large
        }
    }))
    navigationItem.rightBarButtonItem = large
}

사용하는 쪽

  • MyViewController를 present하여 사용
// ViewController.swift
    
@objc func didTapNextButton() {
    showMyViewController()
}

func showMyViewController() {
    let navigationController = UINavigationController(rootViewController: MyViewController())
    present(navigationController, animated: true, completion: nil)
}

* 전체 소스 코드: https://github.com/JK0369/ExBottomSheet

 

* 참고

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

Comments