티스토리 뷰

Swift

Swift 배너 만들기

지용빡 2022. 4. 10. 18:18
반응형
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
링크
«   2025/06   »
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
글 보관함