티스토리 뷰
반응형
SwiftUI를 이용한 배너 만들기
AssetBanner.swift
- 배너 안의 들어갈 값을 저장해 줄 구조체 선언
import UIKit
struct AssetBanner {
let title: String
let description: String
let backgroundColor: UIColor
}
BannerCard.swift
- AssetBanner를 가져와 값을 집어넣고 배너 카드의 View를 생성
import SwiftUI
struct BannerCard: View {
var banner: AssetBanner
var body: some View {
Color(banner.backgroundColor)
.overlay(
VStack {
Text(banner.title)
.font(.title)
Text(banner.description)
.font(.subheadline)
}
)
}
}
struct BannerCard_Previews: PreviewProvider {
static var previews: some View {
let banner0 = AssetBanner(title: "공지사항", description: "추가된 공지사항을 확인하세요", backgroundColor: .red)
BannerCard(banner: banner0)
}
}
PageViewController.swift
- Page의 역할을 할 View를 받는다.
- @Binding이라는 프로퍼티 래퍼를 이용해서 현재 어떤 페이지가 보이고 있는지 상태를 확인 가능하다.
- @Binding 사용시에는 $를 앞에 붙여 Binding 변수임을 나타낸다.
import SwiftUI
import UIKit
struct PageViewController<Page: View>: UIViewControllerRepresentable {
var pages: [Page]
@Binding var currentPage: Int // 현재 어떤 페이지가 보여지고 있는지 확인
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal)
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
pageViewController.setViewControllers(
[context.coordinator.controllers[currentPage]], direction: .forward, animated: true)
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PageViewController
var controllers = [UIViewController]()
init(_ pageViewController: PageViewController) {
parent = pageViewController
controllers = parent.pages.map { UIHostingController(rootView: $0) }
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = controllers.firstIndex(of: viewController) else { return nil }
if index == 0 {
return controllers.last
}
return controllers[index - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let index = controllers.firstIndex(of: viewController) else { return nil }
if index + 1 == controllers.count {
return controllers.first
}
return controllers[index + 1]
}
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 // 애니메이션이 완전히 끝나고 인덱스를 가져갈 수 있도록 설정
}
}
}
}
PageControl.swift
- 각각의 PageController 안에 들어갈 해당 뷰의 대한 Representable
import SwiftUI
import UIKit
// 각각의 PageController 안에 들어갈 해당 뷰의 대한 Representable
struct PageControl: UIViewRepresentable {
var numberOfPages: Int // 전체 페이지의 수
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIPageControl {
let control = UIPageControl()
control.numberOfPages = numberOfPages
control.addTarget(context.coordinator,
action: #selector(Coordinator.updateCurrentPage(sender:)),
for: .valueChanged
)
return control
}
func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
}
class Coordinator: NSObject {
var control: PageControl
init(_ control: PageControl) {
self.control = control
}
@objc func updateCurrentPage(sender: UIPageControl) { // 현재 페이지를 업데이트 할 수 있는 objc 함수
control.currentPage = sender.currentPage
}
}
}
AssetBannerView.swift
- AssetView 하단에 표시될 수 있도록 감싸는 SwiftUI View를 만든다.
- AssetView에 AssetBannerView를 추가해 작동이 잘되는지 확인한다.
import SwiftUI
struct AssetBannerView: View {
let bannerList: [AssetBanner] = [
AssetBanner(title: "공지사항", description: "추가된 공지사항을 확인하세요", backgroundColor: .red),
AssetBanner(title: "주말 이벤트", description: "주말 이벤트를 확인하세요", backgroundColor: .yellow),
AssetBanner(title: "깜짝 이벤트", description: "깜짝 이벤트를 확인하세요", backgroundColor: .blue),
AssetBanner(title: "봄 프로모션", description: "봄 프로모션을 확인하세요", backgroundColor: .systemPink),
]
@State private var currentPage = 0
var body: some View {
let bannerCards = bannerList.map { BannerCard(banner: $0)
}
ZStack(alignment: .bottomTrailing) {
PageViewController(pages: bannerCards, currentPage: $currentPage)
PageControl(numberOfPages: bannerList.count, currentPage: $currentPage)
.frame(width: CGFloat(bannerCards.count * 18))
.padding(.trailing)
}
}
struct AssetBannerView_Previews: PreviewProvider {
static var previews: some View {
AssetBannerView()
.aspectRatio(contentMode: .fit)
}
}
}
반응형
'Swift' 카테고리의 다른 글
Swift TabBar 화면 구현 (0) | 2022.04.12 |
---|---|
Swift UITabBarController (0) | 2022.04.11 |
Swift Grid View 만들기 (0) | 2022.04.09 |
SwiftUI를 이용한 간단한 탭바 만들기 (0) | 2022.04.07 |
Swift GCD(Grand Central Dispatch) (0) | 2022.04.03 |
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- SwiftLint
- UIButton
- 라이트모드
- LazyHStack
- dictionary
- Apple
- swipe
- Java
- Observable
- NavigationLink
- Realtime Database
- github
- Firebase
- Android
- string
- SwiftUI
- gcd
- remote config
- 웹뷰
- RxSwift
- 다크모드
- 문자열
- UIScrollView
- subscript
- ios
- UITabBarController
- Swift
- Alamofire
- WebView
- autolayout
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
글 보관함