Closed TheNoim closed 4 years ago
@TheNoim I'm a bit confused by "A way to use this without passing an array". How is Pager
supposed to know what populates the pages, otherwise? What you're seeing as an argument of the view builder is not an index but a data item. This is needed to populate the page.
All in all, the way you describe Pager
behavior is incorrect. In the example provided, which I think you've got from the documentation and I'm gonna rename, index
it's not just a random integer but a data item. So some might want to page integers from 0 to 10, some other users might want to iterate them from 10 to 20, some others might want to iterate months as you want. This is why "A way to use this without passing an array" doesn't quite makes sense. Pager
takes an data array, a binding and a view builder block. The array is used to build the page at a specific index (that is, next/previous pages). The binding allows you to keep track of the current index.
Just for further clarification:
@State var page: Int = 0
var items = Array(0..<10)
var body: some View {
Pager(page: $page,
data: items,
id: \.identifier,
content: { index in
//
// This isn't just an index. It's an item from data. In this example is an integer
//
Text("Page: \(index)")
})
}
What you would need to do is something like this:
// 9 as we're in October
@State var page: Int = CalendaryMonth.current.monthIndex
@State var oldPage: Int = CalendaryMonth.current.monthIndex
@State var year = 2020
let months = [CalendarMonth(.january), ..., CalendarMonth(.october), CalendarMonth(.november), CalendarMonth(.december)]
var body: some View {
Pager(page: $page,
data: months,
id: \.monthIndex,
content: { month in
// Render month accordingly depending on the year
CalendarViewMonth(month: month, year: year)
})
.loopPages()
.onPageChanged { newPage in
if newPage == 0 && page == 11 { year += 1 }
if newPage == 11 && oldPage == 0 { year -= 1 }
oldPage = newPage
}
}
Pager takes an data array, a binding and a view builder block. The array is used to build the page at a specific index (that is, next/previous pages). The binding allows you to keep track of the current index.
This is not really against my post. My suggestion was more like this: Allow to pass an object conforming to the RandomAccessCollection protocol. This would allow to define your own end and start of Indicies and even updating them dynamically. Currently, you can only pass fixed Data with the index start of zero and a known index end. It would be much cooler if the pager gets no data and the content gets rendered completely dynamic with a passed index. For an infinitive scenario, the pager doesn't need to know the length of an array. It only needs to render the last, the current and next item. It doesn't really need to know what kind of data it is or how many items the data source contains.
I'm not following, could you please show me an example? Even just pseudo-code. I wanna see how you dynamically add data and change the index.
As far as I know, I think you could have a @State
variable for you data
and change it dynamically. This is what I do in the example code, InfiniteExampleView.swift, where I append more items on the fly. If going backwards, you could detect that (the way I was doing for year
in my previous snippet) and insert more items in your array while incrementing the index (so if you append 5 previous months, then your new index is your current index plus 5).
I'm gonna start supporting RandomAccessCollection
with Int
indexes on version 1.13.0. I do the conversion to an Array
internally. See version 1.13.0-beta.1
As far as I can see in your gist, this would be enough for you. Then, if you implement onPageChanged
, you could call your updateCurrentIndex
in this callback:
@State var page = 0 // set here the start index
@State var data: MyRandomAccessCollectionImplementation
Pager(page: $page, data: data, id: \.id) {
// return your View here
}
.onPageChanged { index in
data.updateCurrentIndex(index)
}
Is your feature request related to a problem? Please describe. There is currently no good way library out that supports infinitive page swiping with an unknown size. This could be very useful. Example use case: Infinitiv calendar swipe view. The issue is, a calendar does not have a clear end in both directions. First, when I found this library I thought I finally have a good way to implement a week calendar view. However, then I found out that I still need to pass an array with a known size and a positive index.
Describe the solution you'd like A way to use this without passing an array. Instead of:
this
Describe alternatives you've considered
The alternative would be to allow to pass custom array implementations. For example: Some struct which implements the RandomAccessCollection. Then you could implement your own "array" which auto extends itself in both directions. Negative and positive. RandomAccessCollection supports this:
You can update and define your own end and start.
I tried to implement something similar once by myself. But this is a bit buggy and not really nice: https://gist.github.com/TheNoim/6ca6f35eb830a2d53d6adf04d68e05ba