Skip to content

Instantly share code, notes, and snippets.

@EngOmarElsayed
Last active April 4, 2025 02:21
Show Gist options
  • Save EngOmarElsayed/49506d6b43b74ea5829ffc40680dd055 to your computer and use it in GitHub Desktop.
Save EngOmarElsayed/49506d6b43b74ea5829ffc40680dd055 to your computer and use it in GitHub Desktop.
A custom Container I created to easily create Paging scroll view in swiftUI, article: https://thinkdiffrent.substack.com/p/creating-paging-scrollview-using
#Preview {
@Previewable @State var currentPage = 0
HPagingScrollView(currentPage: $currentPage, spacing: 30, pageWidth: 200, pageHeight: 450) {
RoundedRectangle(cornerRadius: 20)
RoundedRectangle(cornerRadius: 20)
RoundedRectangle(cornerRadius: 20)
RoundedRectangle(cornerRadius: 20)
}
.isScrollDisabled(false)
}
// Mark: HPagingScrollView
struct HPagingScrollView<Content: View>: View {
@Binding var currentPage: Int
let spacing: CGFloat
let pageWidth: CGFloat
let pageHeight: CGFloat
@ViewBuilder let content: () -> Content
private let isScrollDisabled: Bool
init(
currentPage: Binding<Int>,
spacing: CGFloat,
pageWidth: CGFloat,
pageHeight: CGFloat,
@ViewBuilder content: @escaping () -> Content
) {
_currentPage = currentPage
self.spacing = spacing
self.pageWidth = pageWidth
self.pageHeight = pageHeight
self.content = content
self.isScrollDisabled = false
}
var body: some View {
_VariadicView.Tree(
_HPagingScrollViewRoot(
currentPage: $currentPage,
spacing: spacing,
pageWidth: pageWidth,
pageHeight: pageHeight,
isScrollDisabled: isScrollDisabled
)
) {
content()
}
}
}
//MARK: - Disable scroll modifier
extension HPagingScrollView {
private init(
currentPage: Binding<Int>,
spacing: CGFloat,
pageWidth: CGFloat,
pageHeight: CGFloat,
isScrollDisabled: Bool,
@ViewBuilder content: @escaping () -> Content
) {
_currentPage = currentPage
self.spacing = spacing
self.pageWidth = pageWidth
self.pageHeight = pageHeight
self.content = content
self.isScrollDisabled = isScrollDisabled
}
public func isScrollDisabled(_ isScrollDisabled: Bool) -> HPagingScrollView {
HPagingScrollView(
currentPage: $currentPage,
spacing: spacing,
pageWidth: pageWidth,
pageHeight: pageHeight,
isScrollDisabled: isScrollDisabled,
content: content
)
}
}
struct _HPagingScrollViewRoot: _VariadicView_MultiViewRoot {
@Binding var currentPage: Int
let spacing: CGFloat
let pageWidth: CGFloat
let pageHeight: CGFloat
let isScrollDisabled: Bool
private let screenWidth = UIScreen.main.bounds.width
private let screenHeight = UIScreen.main.bounds.height
func body(children: _VariadicView.Children) -> some View {
HStack(spacing: spacing) {
ForEach(children) { child in
child
.frame(width: pageWidth, height: pageHeight)
.id(child.id)
}
}
.padding(.horizontal, (screenWidth-pageWidth)/2)
.offset(x: CGFloat(currentPage) * -(pageWidth+spacing))
.frame(width: screenWidth, alignment: .leading)
.gesture(scrollGesture(totalPages: children.count))
}
private func scrollGesture(totalPages: Int) -> some Gesture {
DragGesture()
.onEnded({ value in
if value.translation.width < -50 && isScrollDisabled == false { incrementCurrentPage(totalPages: totalPages-1) }
if value.translation.width > 50 && isScrollDisabled == false { decrementCurrentPage() }
})
}
private func incrementCurrentPage(totalPages: Int) {
withAnimation {
currentPage = currentPage == totalPages ? currentPage: currentPage+1
}
}
private func decrementCurrentPage() {
withAnimation {
currentPage = currentPage == 0 ? 0: currentPage-1
}
}
}
@Sowsow123
Copy link

Bash zphisher.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment