SwiftUI:如何将 PageView 的 currentPage 与触发视图的传递索引连接起来 [英] SwiftUI: How to connect currentPage of PageView with firing view's passing index

查看:25
本文介绍了SwiftUI:如何将 PageView 的 currentPage 与触发视图的传递索引连接起来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我按照 Apple 的示例 interifying-with-uikit 使用SwiftUI 中的页面视图.我想在我的应用程序中实现它.场景是在 MovieView 中,当用户点击图像列表的图像时,它会触发对 PageView 的调用,并以视图和所选索引为参数.

但是当我点击图像列表的任何项目时,它总是显示第一个元素的页面视图.我尝试在 PageViewinit() 中更改它,但是它不起作用.

在控制台中,我尝试打印一些东西,但我看到 currentPage 没有改变.

ReceivedIdx: 0当前页面:1ReceivedIdx: 3当前页面:1ReceivedIdx: 5当前页面:1

目前,currentPage 连接在 PageView &PageViewCollection,但是如何将 selectedIdx 与它们连接起来?因为它是选择图像的触发点.

电影视图

<代码>...私有结构 ImageList:查看 {var 图像:[ImageViewModel]@State 私有 var showSheet = false@State 私有变量 selectedIdx = 0var主体:一些视图{VStack(对齐:.领先){文本(图像").font(.headline)滚动视图(.水平){HStack(对齐:.top,间距:6){ForEach(0..<images.count, id: \.self) { i inKFImage(来源: .network(self.images[i].fileURL)).resizable().frame(宽度:200).aspectRatio(1.77, contentMode: .fit).onTapGesture {self.selectedIdx = iself.showSheet.toggle()}}}.sheet(isPresented: $showSheet) {PageView(self.images.map { PresentedImageView(image: $0) }, selectedIdx: self.selectedIdx)}}.frame(高度:120)}.padding(.horizo​​ntal).padding(.bottom)}}私有结构 PresentedImageView:查看 {var 图像:ImageViewModelvar主体:一些视图{KFImage(来源: .network(image.fileURL)).resizable()//.frame(width: gr.size.width - 6, 对齐: .center).aspectRatio(1.77, contentMode: .fit)}}...

页面视图

导入 SwiftUIstruct PageView<页面:视图>:视图{var viewControllers: [UIHostingController]var selectedIdx = 0@State var currentPage = 1init(_ views: [Page], selectedIdx: Int) {self.viewControllers = views.map { UIHostingController(rootView: $0) }self.currentPage = selectedIdx打印(ReceivedIdx:\(selectedIdx)")print("当前页面:\(currentPage)")}var主体:一些视图{PageViewController(控制器:viewControllers,currentPage:$currentPage)}}//struct PageView_Previews: PreviewProvider {//静态变量预览:一些视图 {//PageView(features.map { FeatureCard(landmark: $0) })//.aspectRatio(3/2, contentMode: .fit)//}//}

页面视图控制器

导入 SwiftUI导入 UIKitstruct PageViewController: UIViewControllerRepresentable {var 控制器:[UIViewController]@Binding var currentPage: Intfunc makeCoordinator() ->协调员{协调员(自己)}func makeUIViewController(context: Context) ->UIPageViewController {让 pageViewController = UIPageViewController(transitionStyle: .scroll,导航方向:.horizo​​ntal)pageViewController.dataSource = context.coordinatorpageViewController.delegate = context.coordinator返回页面ViewController}func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {pageViewController.setViewControllers([controllers[currentPage]], 方向: .forward, 动画: true)}类协调器:NSObject、UIPageViewControllerDataSource、UIPageViewControllerDelegate {var 父级:PageViewControllerinit(_ pageViewController: PageViewController) {self.parent = pageViewController}func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) ->UIViewController?{守卫让索引 = parent.controllers.firstIndex(of: viewController) else {返回零}如果索引 == 0 {返回 parent.controllers.last}返回 parent.controllers[index - 1]}func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) ->UIViewController?{守卫让索引 = parent.controllers.firstIndex(of: viewController) else {返回零}如果索引 + 1 == parent.controllers.count {返回 parent.controllers.first}返回 parent.controllers[index + 1]}func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating 完成: Bool, previousViewControllers: [UIViewController], transitionCompleted Completed: Bool) {如果完成,让visibleViewController = pageViewController.viewControllers?.first,让 index = parent.controllers.firstIndex(of:visibleViewController){parent.currentPage = 索引}}}}

解决方案

最后,我从stackoverflow 中的这篇帖子中找到了答案

一>.今天早上!

一句话:

<块引用>

SwiftUI 不允许您在初始化程序中更改 @State,但您可以对其进行初始化.

因此,在我的情况下,删除@State currentPage 上的初始值,并在 init() 中直接使用 State(initialValue:) 设置它代码>.

记得在currentPage之前使用_.

导入 SwiftUIstruct PageView<页面:视图>:视图{var viewControllers: [UIHostingController]@State var currentPage: Intinit(_ views: [Page], selectedIdx: Int) {self.viewControllers = views.map { UIHostingController(rootView: $0) }_currentPage = State(initialValue: selectedIdx)}var主体:一些视图{PageViewController(控制器:viewControllers,currentPage:$currentPage)}}

I follow Apple's example interfacing-with-uikit to use PageView in SwiftUI. And I want to implement it in my app. The scenario is that in MovieView, when the user taps an image of image list then it triggers call to PageView with views and selected index as parameters.

But when I click on any item of image list, it always show the page view with the 1st element. I try to change it in init() of PageView, however it is not working.

In console, I try to print something, and I see the currentPage is not changed.

ReceivedIdx: 0
Current page: 1
ReceivedIdx: 3
Current page: 1
ReceivedIdx: 5
Current page: 1

Currently, currentPage is connected between PageView & PageViewCollection, but how to connect selectedIdx with them? Because it is the trigger point for which image is selected.

MovieView

...
private struct ImageList: View {
    var images: [ImageViewModel]
    @State private var showSheet = false
    @State private var selectedIdx = 0

    var body: some View {

        VStack(alignment: .leading) {
            Text("Images")
                .font(.headline)
            ScrollView(.horizontal) {
                HStack(alignment: .top, spacing: 6) {
                    ForEach(0..<images.count, id: \.self) { i in
                        KFImage(source: .network(self.images[i].fileURL))
                            .resizable()
                            .frame(width: 200)
                            .aspectRatio(1.77, contentMode: .fit)
                            .onTapGesture {
                                self.selectedIdx = i
                                self.showSheet.toggle()
                        }
                    }
                }.sheet(isPresented: $showSheet) {
                    PageView(self.images.map { PresentedImageView(image: $0) }, selectedIdx: self.selectedIdx)
                }
            }.frame(height: 120)
        }
        .padding(.horizontal).padding(.bottom)
    }
}

private struct PresentedImageView: View {
    var image: ImageViewModel

    var body: some View {
        KFImage(source: .network(image.fileURL))
        .resizable()
        //.frame(width: gr.size.width - 6, alignment: .center)
        .aspectRatio(1.77, contentMode: .fit)
    }
}
...

PageView

import SwiftUI

struct PageView<Page: View>: View {

    var viewControllers: [UIHostingController<Page>]
    var selectedIdx = 0
    @State var currentPage = 1

    init(_ views: [Page], selectedIdx: Int) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
        self.currentPage = selectedIdx
        print("ReceivedIdx: \(selectedIdx)")
        print("Current page: \(currentPage)")
    }

    var body: some View {
        PageViewController(controllers: viewControllers, currentPage: $currentPage)
    }
}

//struct PageView_Previews: PreviewProvider {
//    static var previews: some View {
//        PageView(features.map { FeatureCard(landmark: $0) })
//            .aspectRatio(3/2, contentMode: .fit)
//    }
//}

PageViewController

import SwiftUI
import UIKit

struct PageViewController: UIViewControllerRepresentable {

    var controllers: [UIViewController]
    @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([controllers[currentPage]], direction: .forward, animated: true)
    }

    class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
        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]
        }

        func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
            if completed,
                let visibleViewController = pageViewController.viewControllers?.first,
            let index = parent.controllers.firstIndex(of: visibleViewController)
            {
                parent.currentPage = index
            }
        }
    }
}

解决方案

Finally, I found the answer From this post in stackoverflow. this morning!

In one word:

SwiftUI doesn't allow you to change @State in the initializer but you can initialize it.

So in my case, remove the initial value on @State currentPage and set it directly using State(initialValue:) in your init().

Remember to use _ before currentPage.

import SwiftUI

struct PageView<Page: View>: View {

    var viewControllers: [UIHostingController<Page>]
    @State var currentPage: Int

    init(_ views: [Page], selectedIdx: Int) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
        _currentPage = State(initialValue: selectedIdx)
    }

    var body: some View {
        PageViewController(controllers: viewControllers, currentPage: $currentPage)
    }
}

这篇关于SwiftUI:如何将 PageView 的 currentPage 与触发视图的传递索引连接起来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆