Skip to content

Instantly share code, notes, and snippets.

@elericuz
Last active March 2, 2025 07:23
Show Gist options
  • Select an option

  • Save elericuz/8a2db54418987cdc56bfceeed5fb95da to your computer and use it in GitHub Desktop.

Select an option

Save elericuz/8a2db54418987cdc56bfceeed5fb95da to your computer and use it in GitHub Desktop.
//
// CarrouselView.swift
// carousel
//
// Created by Eric Valera Miller on 1/03/25.
//
import SwiftUI
struct CarrouselView: View {
@State private var horizontalPadding: CGFloat = 20
@State private var frameWidth: CGFloat = 306
@State private var currentIndex: Int? = 0
@State private var bgImage = "fondo"
var body: some View {
ZStack {
Image(bgImage)
.resizable()
.scaledToFill()
.scaleEffect(1.5, anchor: .center)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
.blur(radius: 24)
.opacity(0.8)
VStack(spacing: 0) {
HStack {
Text("\(Image(systemName: "globe")) Vie, 28 Feb")
.font(Font.custom("Poppins-SemiBold", size: 14))
.foregroundColor(.white)
.padding(8)
.frame(height: 24)
.background(
RoundedRectangle(cornerRadius: 24)
.fill(.gray.opacity(0.5))
)
.frame(maxWidth: .infinity, alignment: .leading)
Circle()
.fill(.gray.opacity(0.5))
.frame(width: 40)
.overlay(
Image(systemName: "person.fill")
.font(Font.custom("Poppins-SemiBold", size: 16))
.foregroundColor(.yellow)
)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.padding(.horizontal)
VStack {
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(1..<4, id: \.self) { index in
Image("img_\(index)")
.resizable()
.aspectRatio(contentMode: .fill)
.scaleEffect(1, anchor: .bottomLeading)
.clipped()
.frame(width: frameWidth, height: 496)
.foregroundStyle(.gray)
.background(.gray.opacity(0.2))
.clipShape(RoundedRectangle(cornerRadius: 24))
.shadow(radius: 10, x: 0, y: 0)
.scrollTransition(.interactive, axis: .horizontal) { effect, phase in
effect.scaleEffect(phase.isIdentity ? 1.0 : 0.85)
}
.id(index)
}
}
.frame(height: 496)
.padding(.horizontal, self.horizontalPadding)
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
.scrollPosition(id: $currentIndex)
}
.frame(maxWidth: .infinity)
.frame(width: .screenWidth)
.padding(.vertical)
.onAppear {
self.horizontalPadding = (.screenWidth - frameWidth) / 2
self.bgImage = "img_1"
}
.onChange(of: currentIndex) { oldValue, newValue in
if let index = newValue {
withAnimation(.easeInOut.delay(0.2)) {
self.bgImage = "img_\(index)"
}
}
}
VStack {
Text("¡Bienvenidos al green, donde cada swing cuenta y la naturaleza es tu compañero de juego!")
.font(Font.custom("Poppins-SemiBold", size: 14))
.multilineTextAlignment(.center)
Text(currentPhrase)
.font(Font.custom("Poppins-SemiBold", size: 20))
.multilineTextAlignment(.center)
.lineLimit(1)
.minimumScaleFactor(0.3)
.lineSpacing(8)
.padding(8)
.animation(.easeInOut(duration: 0.3), value: currentIndex)
.animation(.smooth, value: currentIndex)
.frame(maxWidth: .infinity)
.frame(height: 48)
.background(LinearGradient(gradient: Gradient(colors: [.colorGradient01Start, .colorGradient01End]), startPoint: .topLeading, endPoint: .bottomTrailing))
.clipShape(RoundedRectangle(cornerRadius: 16))
}
.foregroundColor(.white)
.frame(maxWidth: frameWidth)
.padding(.top)
}
.frame(maxHeight: .infinity)
}
}
private var currentPhrase: String {
do {
guard let index = currentIndex, index >= 0, index < Golf.phrases.count else {
throw GolfError.invalidIndex
}
return Golf.phrases[index]
} catch {
return "Frase no disponible" // Valor por defecto en caso de error
}
}
}
class Golf {
static let phrases: [String] = [
"¡Buen tiro!",
"¡Buen tiro!",
"Alinea el putt.",
"¡Cuidado con el bunker!"
]
}
extension CGFloat {
static var screenWidth: CGFloat {
UIScreen.main.bounds.width
}
}
enum GolfError: Error {
case invalidIndex
}
#Preview {
CarrouselView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment