Hello everyone,
I’m working on a tennis calculator app that lets you change the theme based on the tournament you select. to change the theme, the user has 4 cards displayed within a sheet and a button to select them. To swipe between the cards, I’m using a scrollview with scrollTargetLayout and scrollTargetBehaviour(.viewaligned). The problem is that when the sheet loads the cards appear off-centre. Can anyone help me fix it?
//
// ThemeSelector.swift
// CalculatorApp
//
// Created by Pablo Esquivel on 2023-11-01.
//
import SwiftUI
struct ThemeSelector: View {
// @Binding var tournament: String
@Binding var isVisible: Bool
@Binding var theme: Tournament?
@State var id: Tournament?
let tournaments: [Tournament] = [.roland, .wimbledon, .us, .ao]
// init(isVisible: Binding<Bool>, theme: Binding<Tournament?>) {
// _isVisible = isVisible
// _theme = theme
// _id = State(initialValue: theme.wrappedValue)
// }
var body: some View {
ZStack{
Color("\(id?.rawValue ?? "roland")-background")
.ignoresSafeArea()
VStack{
HStack{
Spacer()
Button(action: {
isVisible = false
}, label: {
Image(systemName: "x.circle")
.foregroundStyle(Color("\(id?.rawValue ?? "roland")-main"))
.font(.system(size: 25))
})
}.padding(.trailing, 20.0)
.padding(.vertical, 10)
Text(id?.name ?? "Roland Garros")
.font(.system(size: 40))
.fontWeight(.medium)
.padding(.bottom, 5)
Text(id?.city ?? "Paris, France") //city
.font(.system(size: 16))
.padding(.bottom, 15)
ScrollView(.horizontal, showsIndicators: false) {
HStack{
ForEach (tournaments, id: \.self){ tournament in
Image("\(tournament.rawValue)-court")
.resizable()
.aspectRatio(contentMode: .fit)
.containerRelativeFrame(.horizontal)
.scrollTransition (topLeading: .interactive, bottomTrailing: .interactive, axis: .horizontal) { effect, phase in effect
.scaleEffect(1 - (abs(phase.value)/5))
}
}
}
.scrollTargetLayout()
}
.safeAreaPadding()
.scrollTargetBehavior(.viewAligned)
.scrollPosition(id: $id, anchor: .center)
HStack{
ForEach(tournaments.indices, id: \.self) { index in
// Create a dot for each tournament
let tournament = tournaments[index]
let dotColor = getDotColor(for: tournament)
Circle()
.fill(dotColor)
.frame(width: 5, height: 5)
.padding(.horizontal, 1)
}
}
Button(action: {
theme = id
}, label: {
Text(id?.rawValue == theme?.rawValue ? "Chosen" : "Choose")
.foregroundStyle(Color("\(id?.rawValue ?? "roland")-background"))
}).frame(width: 116, height: 42)
.background(Color("\(id?.rawValue ?? "roland")-side")).opacity(id?.rawValue == theme?.rawValue ? 0.7 : 1)
.cornerRadius(20)
.padding(.top, 20)
}
}
.foregroundStyle(Color("\(id?.rawValue ?? "roland")-display"))
.onAppear {
id = theme
}
}
func getDotColor(for tournament: Tournament) -> Color {
let isSelected = tournament == id
let selectedColor = isSelected ? (tournament.isDarkBackground ? Color.black : Color.white) : Color.gray
return isSelected ? selectedColor : selectedColor.opacity(0.5)
}
}
#Preview {
ThemeSelector(isVisible: Binding.constant(true), theme: Binding.constant(.roland))
}