notsobigcompany / BigUIPaging

A collection of SwiftUI views for handling pages of content
246 stars 13 forks source link

When the content of the view changes, PageView cannot be refreshed #5

Open paulpaulzhang opened 6 months ago

paulpaulzhang commented 6 months ago

This is a very useful and great library, but there are some minor issues: I use coredata as the data source. When the data changes, pageview cannot refresh the current page. It needs to be refreshed after switching the page. I found that it is because the go function has added a check on whether the selection belongs to the current view. Removing the check will make it normal. I hope it can be fixed

func go(

  to value: SelectionValue,

  in pageViewController: UIPageViewController,

  animated: Bool = true

  ) {

    guard let currentViewController = pageViewController.viewControllers?.first as? ContainerViewController else {

      return

    }

     // delete this guard, It can be refreshed normally.
    guard currentViewController.value != value else {

      return

    }

    pageViewController.setViewControllers(

      [makeViewController(value)],

      direction: .forward,

      animated: animated

    )

  }
phillipcaudell commented 6 months ago

Hey Paul, glad you're finding the package useful. Without seeing your code it's tricky to say for sure what's happening, but I suspect it'll have something to do with the view identity. The guard in this case is preventing the same host view controller being created multiple times (good!); the underlying SwiftUI is free to update itself how ever it sees fit. You can attach an id to the view to force a redraw but I would look to see if there is another source of the problem first.

paulpaulzhang commented 6 months ago

Hey Paul, glad you're finding the package useful. Without seeing your code it's tricky to say for sure what's happening, but I suspect it'll have something to do with the view identity. The guard in this case is preventing the same host view controller being created multiple times (good!); the underlying SwiftUI is free to update itself how ever it sees fit. You can attach an id to the view to force a redraw but I would look to see if there is another source of the problem first.

In my view, I placed a scrollview in the pageview, which contains some data cards. On the current page, if the card is deleted, it should disappear from the scrollview, but in reality, it does not disappear

My code like this:

var body: some View {
    PageView(selection: $selection) { value in
        value + 1
    } previous: { value in
        value > 1 ? value - 1 : nil
    } content: { value in
      ScrollView{
                LazyVStack {
                    ForEach(1...totalPages, id: \.self) { value in
                        CardView()
                    }
                }
            }
    }
}

In addition, I tried to add id to scrollview. like ScrollView{}.id(UUID()),but it's useless.

phillipcaudell commented 6 months ago

In your code the ForEach is fixed, so I assume you're talking about the CardView being removed from the PageView itself? If so you'll need to change the identity of the PageView, not the ScrollView (as the closure based initialiser has know way to know). This should ideally be a hash value of whatever your data source is ( .id(mySource) ). Avoid using UUID as this will lead to terrible performance.

paulpaulzhang commented 6 months ago

In your code the ForEach is fixed, so I assume you're talking about the CardView being removed from the PageView itself? If so you'll need to change the identity of the PageView, not the ScrollView (as the closure based initialiser has know way to know). This should ideally be a hash value of whatever your data source is ( .id(mySource) ). Avoid using UUID as this will lead to terrible performance.

Sorry, there may be some problems with the code I gave earlier. This is the modified code. Journals is my data source. It will change, such as adding or deleting content, so ForEach should not be fixed. But I tried using ID (mySourse) on PageView as you mentioned, and now it can run normally! Thanks! I would like to ask more questions. If ForEach is not fixed, is there a better solution?

PageView(selection: $selectedDate) { value in
    let date = (value + 1.days).dateAtStartOf(.day)
    return date
} previous: { value in
    let date = (value - 1.days).dateAtStartOf(.day)
    return date
} content: { value in
    let journals = journalVM.journals[value]!
    ScrollView {
        LazyVStack(spacing: 0) {
            ForEach(journals, id: \.self) { journal in
                TodoCardView(journals)
            }
        }
        .animation(.spring, value: journalVM.journals)

    }
}
.pageViewStyle(.scroll)
.id(journalVM.journals.hashValue)