[SwiftUI] Interfacing with UIKit 2
원문: 튜토리얼 페이지
Section 3. Track the Page in a SwiftUI View’s State
앞서 만들어두었던 UIPageViewController에 몇 페이지 화면인지를 나타내는 UIPageControl을 붙이기 전에 PageView의 현재 페이지가 몇 페이지인지 확인할 수 있도록 수정해보자.
- 우선은 PageViewController에 currentPage 프로퍼티를 선언한다.
- 이 때 currentPage는 binding 프로퍼티로 선언해야 한다. 그리고 updateUIViewController 내에 사용하던 setViewController에도 [currnentPage]로 접근할 수 있도록 수정한다.
PageViewController에 사용되는 currentPage가 @Binding으로 선언되었다면 어딘가에 @State로 선언된 currentPage가 존재할 터.
- 이 프로퍼티는 PageView 파일에 선언해준다.
- 추후에 UIPageControl에서도 이 값을 사용하기 위해서는 UIPageVC와 UIPageControll의 공통 조상에 선언되어야 한다.
- PageView에 currentPage 요소를 나타낼 수 있도록 Text를 추가한다.
- VStack에 넣어서 아래 Text만 추가한다. Page를 움직여도 currentPage가 변화하진 않는다.
그렇다면 currentPage의 숫자를 변경하려면 어떻게 해야하는가! 그것은 4단계에서 확인할 수 있다.
pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted completed: Bool)
구현하기- 요 메서드는 UIPageViewControllerDelegate에 있는 메서드로, 우리의 PageViewController 내의 Coordinator에서 구현해준다.
- dataSource 지정을 해준 것처럼 delegate도 makeUIViewController에서 context.coordinator로 지정해주어야 한다.
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
if completed,
let visibleViewController = pageViewController.viewControllers?.first,
let index = controllers.firstIndex(of: visibleViewController) {
parent.currentPage = index
}
}
page를 움직이는 animating이 끝나면 currentPage를 노출된 viewController의 index로 업데이트 해준다. Binding 된 값이기 때문에 currentPage가 변경되면 아래처럼 Text도 변한다.
Section 4. Add a Custom Page Control
이제 currentPage가 변화하는 것도 확인했으니 진짜 UIPageControl을 붙여보자. UIPageControl은 UIView에 속하는 친구이기 때문에 UIViewRepresentable 을 준수하는 struct로 구현해야 한다.
- PageControl.swift 생성
- UIViewRepresentable을 준수해야 한다. UIViewControllerRepresentable과 구현해야 할 메서드는 같다. (life cycle도 같다.)
import SwiftUI
import UIKit
struct PageControl: UIViewRepresentable {
var numberOfPages: Int
@Binding var currentPage: Int
func makeUIView(context: Context) -> UIPageControl {
let control = UIPageControl()
control.numberOfPages = numberOfPages
return control
}
func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
}
}
UIPageControl을 반환하고, control이 표기해야 할 page 수는 외부에서 주입받는다. currentPage는 PageView의 currentPage를 바인딩한 값을 사용한다.
- PageView에 PageControl 추가하기
- VStack을 ZStack으로 변경해 PageViewController 위에 PageControl이 노출되도록 한다.
- PageControl을 눌렀을 때도 이동하도록 수정
- 2번까지 구현하고 나면 화면의 PageControl을 눌렀을 때 PageControl은 변경되지만 이미지는 변경되지 않기 때문에 정상적으로 화면이 넘어갈 수 있도록 currentPage를 업데이트 해 줄 필요가 있다.
- 업데이트를 할 때는 Coordinator를 선언해 해당 클래스 내에서 값을 조작하도록 한다.
valueChange일 때 updateCurrentPage가 호출되도록 makeUIView에서 addTarget을 사용해 control에 동작을 지정해주었다.
- CategoryHome에서 임시로 넣어두었던 이미지 대신 PageView를 추가한다.
최종적으로 실행하면 다음과 같이 동작한다.
마무리
watchOS와 macOS 부분을 제외하면 SwiftUI Tutorial에 있는 모든 내용을 다 정리했다. SearchApp을 만들어보는 데 아주 큰 도움이 됐다. 확실히 튜토리얼을 끝내고 나니까 조금은 swiftUI에 적응이 된 것 같은 느낌? 정확히 알아서 내 것으로 만드는 게 중요하겠지만 일단은 익숙해진 것만으로도 뿌듯하다 😎
이제 SearchApp 마무리 지으러 가봐야겠다!!
Leave a comment