-
Swift Bottom Sheet 바텀시트 구현하는 방법 + 동적 높이 할당개발/Swift 2023. 5. 24. 17:02
Modern Collection View 와 MVVM 패턴 가이드
보통 navigation 의 present 함수를 통해 버텀 시트를 구현 하면 좋지만
해당하는 높이가 아닌 낮은 높이의 바텀시트를 구현 하기 위해서는 결국
Custom 하게 만들어야 한다.
그러려면 결국 ViewController 안에 배경을 흐릿하게 하고
안에 Content View 를 넣어주어 해당 View를 BottomSheet 처럼 꾸며야한다.
우선 띄울때 이전 화면에서 present로 띄우기 때문에
BottomSheet VC init 에서 style 를 넣어준다.
이렇게 하면 pageSheet 형태로 뜨지 않고 전체 영역을 먹음
self.modalPresentationStyle = .overCurrentContext
컨테이너 뷰를 정의해준다. 이게 바텀시트가 될예정
흰 배경에 Radius 넣어주고 Clips 로 잘라주고
위 왼쪽 오른쪽만 코너를 넣어준다.
private let containerView = { let view = UIView(backgroundColor: .white500) view.clipsToBounds = true view.layer.cornerRadius = 10 view.layer.maskedCorners = CACornerMask(arrayLiteral: .layerMinXMinYCorner, .layerMaxXMinYCorner) return view }()
전체 view의 배경을 어둡게 해주고
view.backgroundColor = .black.withAlphaComponent(0.8)
바텀시트 안에 들어갈 UI 들을 저 containerView 안에 넣어주면 된다.
여기서 만약 바텀시트처럼 밑에서 위로 올라오는 애니메이션을 구현하려면
제약조건을 설정 해주면 된다.
Container view 안에 들어갈 UI들의 높이 제약조건은 꼭 잘 설정해줘야한다.
//viewdidLoad에서 높이 0으로 지정 containerView.snp.makeConstraints { make in make.leading.trailing.bottom.equalToSuperview() make.height.equalTo(0) } //view did appear public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) UIView.animate(withDuration: 0.3) { [weak self] in self?.containerView.snp.updateConstraints { make in make.height.equalTo(536) } self?.view.layoutIfNeeded() } }
애니메이션과 함께 높이를 변경 시켜주면 애니메이션 이 먹는다.
닫을때 밑으로 내리고싶으면 컨테이너뷰의 bottom 을 밑으로 내려주면 된다
UIView.animate(withDuration: 0.3) { [weak self] in self?.containerView.snp.updateConstraints { make in make.bottom.equalTo(536) } self?.view.backgroundColor = .clear self?.view.layoutIfNeeded() } completion: { [weak self] _ in self?.dismiss(animated: true, completion: completion) }
그런데 만약 높이가 동적이라면?
이 바텀시트 안에 Tableview를 사용해서 높이를 저렇게 지정해 줄수 없다면 조금 달라진다.
처음제약 조건에 containerview는 어차피 테이블뷰 높이에 따라 바뀌므로
tableview를 container 에 맞춰준후 높이 0을 넣어준다.
//viewdidLoad containerView.snp.makeConstraints { make in make.leading.equalToSuperview() make.trailing.equalToSuperview() make.bottom.equalTo(0) } tableView.snp.makeConstraints { make in make.leading.equalTo(20) make.trailing.equalTo(-20) make.top.bottom.equalToSuperview() make.height.equalTo(0) }
높이를 지정해주지 않으면 cell provider 자체가 호출이 안되서 cell 이 그려지지도 않느다.
여기서 높이를 구하느라 삽질을 많이했느데
가장 효과적인 방법은 Observing을 사용하는거이었다.
tableView.rx.observe(CGSize.self, #keyPath(UITableView.contentSize)) .debounce(.milliseconds(100), scheduler: MainScheduler.instance) .bind { [weak self] size in ///이렇게 높이를 트래킹 할수가 있다. guard let s = self, var height = size?.height else { return } //아래 로직은 디바이스보다 커지는 경우를 막기 위함 if height > Config.Device.SCREEN_HEIGHT - 60 { height = Config.Device.SCREEN_HEIGHT - 60 } s.tableViewHeight = height // 높이 지정 UIView.animate(withDuration: 0.3) { s.pointCouponTableView.snp.updateConstraints { make in make.height.equalTo(height) } self?.view.layoutIfNeeded() } }.disposed(by: disposeBag)
닫는 부분은 위와 같이 containerview bottom을 아래로 내려주면 된다.
위에서 s.tableViewHeight 를 저장해 두었기 때문에 그걸 쓰면 된다.
'개발 > Swift' 카테고리의 다른 글
Collection View가 들어있는 동적 높이의 Table view Cell 구현하기 (0) 2023.06.18 Tableview와 스크롤을 다루는 방법 (0) 2023.05.31 Swift Tooltip 구현하는 방법 (2) 2023.05.21 확장 축소 가능한 동적 높이 TableView 구현 하기 (0) 2023.04.16 Relay를 사용하면 무조건 메인스레드 일까 (0) 2023.04.02