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。
我正在尝试将 .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。