PageViewController - 白色背景

PageViewController - white background

我正在尝试将 .background 修饰符应用于由 PageViewController 表示的卡片。

红色背景没有应用到我的卡片上,因为卡片似乎有默认的白色背景。

import SwiftUI

struct PageView<Page:View>: View {

    var viewControllers: [UIHostingController<Page>]

    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: [=10=])}
    }

    var body: some View {


        ZStack {

            Color.black
                .edgesIgnoringSafeArea(.all)

            PageViewController(controllers: viewControllers)
                .background(Color.red)

        }


    }

}

struct PageView_Previews: PreviewProvider {
    static var previews: some View {
        PageView(cards.map { OnboardingCardView(card: [=10=]) })
    }
}

每张卡片都来自 CardView,我的卡片没有应用任何背景。

这是我的 pageViewController 代码:

    import SwiftUI

struct PageViewController: UIViewControllerRepresentable {

    var controllers: [UIViewController]

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIPageViewController {

        let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)

        pageViewController.dataSource = context.coordinator

        return pageViewController
    }

    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {

        pageViewController.setViewControllers([controllers[0]], direction: .forward, animated: true)
    }

    class Coordinator: NSObject, UIPageViewControllerDataSource {
        var parent: PageViewController

        init(_ pageViewController: PageViewController) {
            self.parent = pageViewController
        }

        func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {

            guard let index = parent.controllers.firstIndex(of: viewController) else {
                return nil
            }

            if index == 0 {
                return parent.controllers.last
            }

            return parent.controllers[index-1]

        }

        func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

            guard let index = parent.controllers.firstIndex(of: viewController) else {
                return nil
            }

            if index + 1 == parent.controllers.count {
                return parent.controllers.first
            }

            return parent.controllers[index+1]

        }

    }

}

这里有什么问题? 非常感谢。

默认情况下,在您的 UIHostingController 中为每张卡片设置背景。您可以手动将背景颜色设置为.clear 以使SwiftUI 背景生效:

struct PageView<Page:View>: View {

    var viewControllers: [UIHostingController<Page>]

    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: [=10=])}
        for viewController in viewControllers{
            viewController.view.backgroundColor = .clear
        }

    }
...
}

检查我对 UIPageViewController 的完整 SwiftUI 实现。不使用UIKit,这样会更容易控制。

import SwiftUI
extension OnboardingCard{
    static var test: [OnboardingCard]{
        [
        OnboardingCard(image: "onboarding", title: "Card 1", description: "Card 1 description."),
        OnboardingCard(image: "onboarding", title: "Card 2", description: "Card 2 description."),
        OnboardingCard(image: "onboarding", title: "Card 3", description: "Card 4 description.")
        ]
    }
}

struct ContentView: View {
    var directionForward = true
    @State var currentCard: OnboardingCard
    var cards: [OnboardingCard]
    @State var xOffset: CGFloat = 0
    init(cards newCards: [OnboardingCard]){
        self.cards = newCards
        guard let startCard = newCards.first else {fatalError("no cards")}
        self._currentCard = State(initialValue: startCard)
    }
    var body: some View {
        GeometryReader{geometry in
            HStack{
                ForEach(self.cardsSorted()){card in
                    OnboardingCardView(card: card)
                        .frame(width: geometry.size.width)
                }
            }
            .offset(x: self.xOffset, y: 0)
            .gesture(DragGesture()
            .onChanged(){value in
                self.xOffset = value.location.x - value.startLocation.x
                }
            .onEnded(){value in
                let inPercent = 100 * self.xOffset / (geometry.size.width / 2)
                let changedCount = inPercent / 100
                if changedCount < -1{//drag left to go to next one
                    guard let currentCardInd = self.cards.firstIndex(where: {[=10=].id == self.currentCard.id}) else{fatalError("cant find current card")}
                    let nextInd = self.cards.index(currentCardInd, offsetBy: Int(-changedCount))
                    if self.cards.indices.contains(nextInd){
                        self.currentCard = self.cards[nextInd]
                        self.xOffset = geometry.size.width + self.xOffset
                    }else{
                        guard let firstCard = self.cards.first else{fatalError("cant get first card")}
                        self.currentCard = firstCard
                        self.xOffset = geometry.size.width + self.xOffset
                    }
                }else if changedCount > 1{//drag right to go to previos one
                    guard let currentCardInd = self.cards.firstIndex(where: {[=10=].id == self.currentCard.id}) else{fatalError("cant find current card")}
                    let previosInd = self.cards.index(currentCardInd, offsetBy: Int(-changedCount))
                    if self.cards.indices.contains(previosInd){
                        self.currentCard = self.cards[previosInd]
                        self.xOffset = -geometry.size.width + self.xOffset
                    }else{
                        guard let lastCard = self.cards.last else{fatalError("cant get last card")}
                        self.currentCard = lastCard
                        self.xOffset = -geometry.size.width + self.xOffset
                    }
                }

                withAnimation(.easeInOut(duration: 0.5)){
                    self.xOffset = 0
                }
            })
        }
    }
    func cardsSorted() -> [OnboardingCard]{
        guard let currentCardInd = self.cards.firstIndex(where: {[=10=].id == self.currentCard.id}) else{fatalError("cant find current card")}
        guard let firstInd = self.cards.firstIndex(where: {[=10=].id == cards.first?.id}) else{fatalError("cant find current card")}
        guard let lastInd = self.cards.firstIndex(where: {[=10=].id == cards.last?.id}) else{fatalError("cant find current card")}
        var nextInd = self.cards.index(after: currentCardInd)
        if self.cards.indices.contains(nextInd) == false{
            nextInd = firstInd
        }
        var previosInd = self.cards.index(before: currentCardInd)
        if self.cards.indices.contains(previosInd) == false{
            previosInd = lastInd
        }
        return [self.cards[previosInd], self.cards[currentCardInd],self.cards[nextInd]]
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(cards: OnboardingCard.test)
    }
}

代码少,逻辑透明。如果需要,您可以修改检查以调整开关灵敏度(通过编辑比较 if changedCount > 1)。您可以使用手势终点预测来计算和调整动画速度,甚至可以一次切换多张卡片。这完全取决于你。或者您可以直接使用 if。