-
-
Save mecid/e0d4d6652ccc8b5737449a01ee8cbc6f to your computer and use it in GitHub Desktop.
// | |
// PagerView.swift | |
// | |
// Created by Majid Jabrayilov on 12/5/19. | |
// Copyright © 2019 Majid Jabrayilov. All rights reserved. | |
// | |
import SwiftUI | |
struct PagerView<Content: View>: View { | |
let pageCount: Int | |
@Binding var currentIndex: Int | |
let content: Content | |
@GestureState private var translation: CGFloat = 0 | |
init(pageCount: Int, currentIndex: Binding<Int>, @ViewBuilder content: () -> Content) { | |
self.pageCount = pageCount | |
self._currentIndex = currentIndex | |
self.content = content() | |
} | |
var body: some View { | |
GeometryReader { geometry in | |
HStack(spacing: 0) { | |
self.content.frame(width: geometry.size.width) | |
} | |
.frame(width: geometry.size.width, alignment: .leading) | |
.offset(x: -CGFloat(self.currentIndex) * geometry.size.width) | |
.offset(x: self.translation) | |
.animation(.interactiveSpring()) | |
.gesture( | |
DragGesture().updating(self.$translation) { value, state, _ in | |
state = value.translation.width | |
}.onEnded { value in | |
let offset = value.translation.width / geometry.size.width | |
let newIndex = (CGFloat(self.currentIndex) - offset).rounded() | |
self.currentIndex = min(max(Int(newIndex), 0), self.pageCount - 1) | |
} | |
) | |
} | |
} | |
} |
This will more smoothly
import Foundation
import SwiftUI
struct PagerView<Content: View>: View {
let pageCount: Int
@State var ignore: Bool = false
@Binding var currentIndex: Int {
didSet {
if (!ignore) {
currentFloatIndex = CGFloat(currentIndex)
}
}
}
@State var currentFloatIndex: CGFloat = 0 {
didSet {
ignore = true
currentIndex = min(max(Int(currentFloatIndex.rounded()), 0), self.pageCount - 1)
ignore = false
}
}
let content: Content
@GestureState private var offsetX: CGFloat = 0
init(pageCount: Int, currentIndex: Binding<Int>, @ViewBuilder content: () -> Content) {
self.pageCount = pageCount
self._currentIndex = currentIndex
self.content = content()
}
var body: some View {
GeometryReader { geometry in
HStack(spacing: 0) {
self.content.frame(width: geometry.size.width)
}
.frame(width: geometry.size.width, alignment: .leading)
.offset(x: -CGFloat(self.currentFloatIndex) * geometry.size.width)
.offset(x: self.offsetX)
.animation(.linear, value:offsetX)
.highPriorityGesture(
DragGesture().updating(self.$offsetX) { value, state, _ in
state = value.translation.width
}
.onEnded({ (value) in
let offset = value.translation.width / geometry.size.width
let offsetPredicted = value.predictedEndTranslation.width / geometry.size.width
let newIndex = CGFloat(self.currentFloatIndex) - offset
self.currentFloatIndex = newIndex
withAnimation(.easeOut) {
if(offsetPredicted < -0.5 && offset > -0.5) {
self.currentFloatIndex = CGFloat(min(max(Int(newIndex.rounded() + 1), 0), self.pageCount - 1))
} else if (offsetPredicted > 0.5 && offset < 0.5) {
self.currentFloatIndex = CGFloat(min(max(Int(newIndex.rounded() - 1), 0), self.pageCount - 1))
} else {
self.currentFloatIndex = CGFloat(min(max(Int(newIndex.rounded()), 0), self.pageCount - 1))
}
}
})
)
}
.onChange(of: currentIndex, perform: { value in
print("index changed")
// this is probably animated twice, if the tab change occurs because of the drag gesture
withAnimation(.easeOut) {
currentFloatIndex = CGFloat(value)
}
})
}
}
Is there any way to load the views lazily?
@samilao101 did you try to use LazyHStack instead of HStack?
@mecid I did, but the issue is that in order for a lazyhstack to become lazy it needs to be imbedded in a scrollview, and if you do that, you essentially lose the pagination feature.
@samilao101 oh, you're right. Maybe TabView with Page style will work for you better?
So isn't the lazy this approach....Load all contents and onAppear
@pjcau sorry I am not sure I understand what you mean
@pjcau sorry I am not sure I understand what you mean
IN this way, if you want load a array of DetalView for example, so load in one step all init and onAppear(). So it's not good. But fix it with TabView with Page style.
@pjcau did you manage to integrate ScrollView in order to achieve lazy loading?
My team recently delivered PagerTabStripView, a new Open Source for Pager Tab views. This is the GitHub repo. You can read an introduction in this post.
![enter image description here](https://camo.githubusercontent.com/3a1a2b1f3671ce6cfdd4bae081be130ee037a2d3525f9368abb7cca8049f1eeb/68747470733a2f2f692e737461636b2e696d6775722e636f6d2f5a705368662e676966)
Here is an example gif!
We'll appreciate it if you can take a look! If you like the library, want to contribute to the project, or need some help using it, please reach out to us, open an issue or a pull request.