ios 通过页面视图控制器Swiftui从视图传递滚动视图偏移值

tjjdgumg  于 2022-11-19  发布在  iOS
关注(0)|答案(1)|浏览(193)

我试图显示页面控制器一样,第二次截图时,去底部和隐藏顶部视图。

第一个屏幕截图

Screen Shot

第二个屏幕截图

Screenshot
代码:-

struct MainHomePage: View {

@State private var day = 0
@State var days: [HostingController<CenterHomeView>] = [HostingController(rootView: CenterHomeView(day: .constant(0))),HostingController(rootView: CenterHomeView(day: .constant(1))),HostingController(rootView: CenterHomeView(day: .constant(2))),HostingController(rootView: CenterHomeView(day: .constant(3))),HostingController(rootView: CenterHomeView(day: .constant(4))),HostingController(rootView: CenterHomeView(day: .constant(5))),HostingController(rootView: CenterHomeView(day: .constant(6)))]

init() {
    var pages = [HostingController<CenterHomeView>] ()
    for index in 0..<7 {
        pages.append(HostingController(rootView: CenterHomeView(day: .constant(index))))
    }
    self.days = pages
}

var body: some View {
    TabView   {
        ScrolViewSetOffsetView(day: $day, views: $days)
            .tabItem {
                Image(systemName: "person")
                Text("Profile")
              }
          }
      }
 }

struct ScrolViewSetOffsetView: View {

@Binding var day: Int
@State private var offSet = 0.0
@Binding var views: [HostingController<CenterHomeView>]

var body: some View {
    NavigationView {
        ZStack {
            VStack {
                if offSet <= 80  {
                    DayTopView(currentDay: $day)
                } else {
                    PageControl(numberOfPages: 7, currentPage: self.$day)
                        .frame(width: CGFloat(7 * 18))
                        .padding(.trailing)
                }
                PageViewController(pages: views, currentPage: $day)
               }
            }
        }
    }
  }

struct CenterHomeView: View {

@Binding var day: Int

var body: some View {
    ZStack {
        if day == 0 {
            ScrollView {
                VStack {
                    ForEach(0..<100){ index in
                        Text("\(index)")
                    }.frame(width: 100)
                }.background(GeometryReader {
                    Color.clear.preference(key: ViewOffsetKey.self,
                                           value: -$0.frame(in: .named("scroll")).origin.y)
                }).onPreferenceChange(ViewOffsetKey.self) {
                    print("offset >> \($0)")
                }
            }.coordinateSpace(name: "scroll")
        }else if day == 1 {
            Color.blue
        }else if day == 2 {
            Color.gray
        }else if day == 3 {
            Color.green
        }else if day == 4 {
            Color.red
        }else if day == 5 {
            Color.yellow
        }else if day == 6 {
            Color.pink
        }else if day == 7 {
            Color.blue
        }
        Spacer()
    }.hiddenNavigationBarStyle()
    }
  }


struct DayTopView: View {

@Binding var currentDay : Int
var active = false

var body: some View {
    Group {
        VStack {
            HStack(alignment: .center, spacing: 6) {
                ForEach(0..<7) { offset in
                    DayButton(offset: offset, active: offset == currentDay) { offset in
                        currentDay = offset
                    }
                }
            }
            .padding(.top)
            .padding(.bottom)
            Spacer().frame(height: 5)
          }
       }
    }
  }

 final class HostingController<T: View>: UIHostingController<T> {
 override var preferredStatusBarStyle: UIStatusBarStyle {
    .lightContent
  }
}

struct PageControl: UIViewRepresentable {
var numberOfPages: Int
@Binding var currentPage: Int

func makeUIView(context: Context) -> UIPageControl {
    let control = UIPageControl()
    control.numberOfPages = numberOfPages
    control.currentPageIndicatorTintColor = UIColor(displayP3Red: 190/255, green: 251/255, blue: 0/255, alpha: 1.0)
    control.pageIndicatorTintColor = UIColor(displayP3Red: 142/255, green: 144/255, blue: 144/255, alpha: 1.0)
    return control
}

func updateUIView(_ uiView: UIPageControl, context: Context) {
    uiView.currentPage = currentPage
  }
}

struct PageViewController: UIViewControllerRepresentable {
var pages: [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) {    
    context.coordinator.parent = self
    pageViewController.setViewControllers([pages[currentPage]], direction: .forward, animated: false)
}

class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate,UIScrollViewDelegate {
    var parent: PageViewController
    
    init(_ pageViewController: PageViewController) {
        self.parent = pageViewController
    }
    
    func pageViewController(
        _ pageViewController: UIPageViewController,
        viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = parent.pages.firstIndex(of: viewController) else {
            return nil
        }
        
        if index == 0 {
            return nil
        }
        
        return parent.pages[index - 1]
    }
    
    func pageViewController(
        _ pageViewController: UIPageViewController,
        viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = parent.pages.firstIndex(of: viewController) else {
            return nil
        }
        if index + 1 == parent.pages.count {
            return nil
        }
        
        return parent.pages[index + 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if completed,
           let visibleViewController = pageViewController.viewControllers?.first,
           let index = parent.pages.firstIndex(of: visibleViewController) {
            parent.currentPage = index
          }
        }
    }
 }

有人能请解释给我如何显示页面控制器在顶部时滚动到底部,我得到了滚动视图偏移,但我不知道如何在主屏幕中传递。我已经尝试实现以上,但还没有结果。
任何帮助都将不胜感激。
先谢谢你。

eufgjt7s

eufgjt7s1#

我简化了它,因为它是复杂的使用您的代码,因为它是。
ObservableScrollView检测滚动条的变化,并在滚动条位于顶部时分支视图。
https://imgur.com/gallery/RtuRutT

import SwiftUI

struct ContentView: View {
    
    @State var scrollIsTop: Bool = true
    
    var body: some View {
        
        VStack {
            ScrollView(.horizontal) {
                
                if scrollIsTop { // <- your first screenshot view is in here
                    HStack {
                        ForEach(1..<100) {
                            Text("top \($0)")
                                .frame(height: 55)
                                .background(.red)
                        }
                    }
                } else { // <- your second screenshot view is in here
                    HStack {
                        ForEach(1..<100) {
                            Text("top \($0)")
                                .frame(height: 30)
                                .background(.blue)
                        }
                    }
                }
            }

            ObservableScrollView() { proxy in
                ForEach(1..<100) {
                    Text("num \($0)")
                        .frame(width: UIScreen.main.bounds.width, height: 55)
                }
            }
            .onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { newValue in
                scrollIsTop = newValue > 0 ? false : true
            }
        }
        .frame(width: UIScreen.main.bounds.width)
    }
    
    struct ScrollViewOffsetPreferenceKey: PreferenceKey {
        static var defaultValue = CGFloat.zero
        
        static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
            value += nextValue()
        }
    }
    
    struct ObservableScrollView<Content>: View where Content : View {
        @Namespace var scrollSpace
        
        let content: (ScrollViewProxy) -> Content
        
        init(
             @ViewBuilder content: @escaping (ScrollViewProxy) -> Content) {
            self.content = content
        }
        
        var body: some View {
            ScrollView {
                ScrollViewReader { proxy in
                    content(proxy)
                        .background(GeometryReader { geo in
                            
                            let offset = -geo.frame(in: .named(scrollSpace)).minY
                            Color.clear
                                .preference(key: ScrollViewOffsetPreferenceKey.self,
                                            value: offset)
                        })
                }
            }
            .coordinateSpace(name: scrollSpace)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

相关问题