Skip to content

Instantly share code, notes, and snippets.

@The-Igor
Last active November 16, 2023 07:21
Show Gist options
  • Save The-Igor/224e888787e212014eb899b87532cec6 to your computer and use it in GitHub Desktop.
Save The-Igor/224e888787e212014eb899b87532cec6 to your computer and use it in GitHub Desktop.
//
// ContentView.swift
//
// Carousel with Parallax Effect SwiftUI
// Created by Igor Shelopaev on 10.08.2022.
//
import SwiftUI
import Combine
struct ContentView: View {
@State private var selected = 0
@State private var current: Int = 0
@State private var opacity: CGFloat = 1
private let pass: PassthroughSubject<Void, Never>
private let publisher: AnyPublisher<Void, Never>
private let lenght : CGFloat = 0.5
// MARK: - Life circle
init() {
let pass = PassthroughSubject<Void, Never>()
publisher = pass.delay(for: .seconds(lenght), scheduler: RunLoop.main, options: .none)
.eraseToAnyPublisher()
self.pass = pass
}
var body: some View {
ZStack { tabTpl }
.background(blurBg)
.onChange(of: selected, perform: onChange)
.onReceive(publisher, perform: onReceive)
.preferredColorScheme(.dark)
}
// MARK: - Private
private var blurBg : some View{
GeometryReader { _ in
Image("w\(selected + 1)")
.resizable()
.scaledToFill()
.blur(radius: 25)
.scaleEffect(1.1)
Image("w\(current + 1)")
.resizable()
.scaledToFill()
.blur(radius: 25)
.scaleEffect(1.1)
.opacity(opacity)
}
}
private var tabTpl : some View{
TabView(selection: $selected) {
ForEach(1..<6) { index in
GeometryReader { proxy in
let minX = proxy.frame(in: .global).minX
ZStack { Color.clear }
.background(
Image("w\(index)")
.resizable()
.scaledToFill()
.offset(x: -minX / 2)
.opacity(0.9)
)
.mask(RoundedRectangle(cornerRadius: 32, style: .continuous))
}.padding(.horizontal)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
.shadow(color: .black.opacity(0.25), radius: 5, x: 5, y: 50)
.shadow(color: .black.opacity(0.15), radius: 5, x: 5, y: -5)
}
private func onChange(selected : Int) {
withAnimation(.linear(duration: lenght)) {
opacity = 0
}
pass.send()
}
private func onReceive(){
withAnimation(.linear(duration: lenght)) {
current = selected
opacity = 1
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment