diff --git a/Sources/ACarousel/ACarousel.swift b/Sources/ACarousel/ACarousel.swift index 1cc1664..6d62e5f 100644 --- a/Sources/ACarousel/ACarousel.swift +++ b/Sources/ACarousel/ACarousel.swift @@ -74,9 +74,10 @@ extension ACarousel { /// - autoScroll: A enum that define view to scroll automatically. See /// ``ACarouselAutoScroll``. default is `inactive`. /// - content: The view builder that creates views dynamically. - public init(_ data: Data, id: KeyPath, index: Binding = .constant(0), spacing: CGFloat = 10, headspace: CGFloat = 10, sidesScaling: CGFloat = 0.8, isWrap: Bool = false, autoScroll: ACarouselAutoScroll = .inactive, canMove: Bool = true, @ViewBuilder content: @escaping (Data.Element) -> Content) { - - self.viewModel = ACarouselViewModel(data, id: id, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove) + /// - animation: A custom animation for offset changes. Default value is ``Animation.spring()`` + public init(_ data: Data, id: KeyPath, index: Binding = .constant(0), spacing: CGFloat = 10, headspace: CGFloat = 10, sidesScaling: CGFloat = 0.8, isWrap: Bool = false, autoScroll: ACarouselAutoScroll = .inactive, canMove: Bool = true, @ViewBuilder content: @escaping (Data.Element) -> Content, animation: (() -> Animation)? = nil) { + + self.viewModel = ACarouselViewModel(data, id: id, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove, animation: animation) self.content = content } @@ -100,9 +101,10 @@ extension ACarousel where ID == Data.Element.ID, Data.Element : Identifiable { /// - autoScroll: A enum that define view to scroll automatically. See /// ``ACarouselAutoScroll``. default is `inactive`. /// - content: The view builder that creates views dynamically. - public init(_ data: Data, index: Binding = .constant(0), spacing: CGFloat = 10, headspace: CGFloat = 10, sidesScaling: CGFloat = 0.8, isWrap: Bool = false, autoScroll: ACarouselAutoScroll = .inactive, canMove: Bool = true, @ViewBuilder content: @escaping (Data.Element) -> Content) { - - self.viewModel = ACarouselViewModel(data, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove) + /// - animation: A custom animation for offset changes. Default value is ``Animation.spring()`` + public init(_ data: Data, index: Binding = .constant(0), spacing: CGFloat = 10, headspace: CGFloat = 10, sidesScaling: CGFloat = 0.8, isWrap: Bool = false, autoScroll: ACarouselAutoScroll = .inactive, canMove: Bool = true, @ViewBuilder content: @escaping (Data.Element) -> Content, animation: (() -> Animation)? = nil) { + + self.viewModel = ACarouselViewModel(data, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove, animation: animation) self.content = content } diff --git a/Sources/ACarousel/ACarouselViewModel.swift b/Sources/ACarousel/ACarouselViewModel.swift index 79199ef..30a1a15 100644 --- a/Sources/ACarousel/ACarouselViewModel.swift +++ b/Sources/ACarousel/ACarouselViewModel.swift @@ -36,9 +36,10 @@ class ACarouselViewModel: ObservableObject where Data : RandomAccessCo private let _sidesScaling: CGFloat private let _autoScroll: ACarouselAutoScroll private let _canMove: Bool - - init(_ data: Data, id: KeyPath, index: Binding, spacing: CGFloat, headspace: CGFloat, sidesScaling: CGFloat, isWrap: Bool, autoScroll: ACarouselAutoScroll, canMove: Bool) { - + private let _animation: (() -> Animation)? + + init(_ data: Data, id: KeyPath, index: Binding, spacing: CGFloat, headspace: CGFloat, sidesScaling: CGFloat, isWrap: Bool, autoScroll: ACarouselAutoScroll, canMove: Bool, animation: (() -> Animation)? = nil) { + guard index.wrappedValue < data.count else { fatalError("The index should be less than the count of data ") } @@ -51,7 +52,8 @@ class ACarouselViewModel: ObservableObject where Data : RandomAccessCo self._sidesScaling = sidesScaling self._autoScroll = autoScroll self._canMove = canMove - + self._animation = animation + if data.count > 1 && isWrap { activeIndex = index.wrappedValue + 1 } else { @@ -105,8 +107,8 @@ class ACarouselViewModel: ObservableObject where Data : RandomAccessCo extension ACarouselViewModel where ID == Data.Element.ID, Data.Element : Identifiable { - convenience init(_ data: Data, index: Binding, spacing: CGFloat, headspace: CGFloat, sidesScaling: CGFloat, isWrap: Bool, autoScroll: ACarouselAutoScroll, canMove: Bool) { - self.init(data, id: \.id, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove) + convenience init(_ data: Data, index: Binding, spacing: CGFloat, headspace: CGFloat, sidesScaling: CGFloat, isWrap: Bool, autoScroll: ACarouselAutoScroll, canMove: Bool, animation: (() -> Animation)? = nil) { + self.init(data, id: \.id, index: index, spacing: spacing, headspace: headspace, sidesScaling: sidesScaling, isWrap: isWrap, autoScroll: autoScroll, canMove: canMove, animation: animation) } } @@ -136,9 +138,9 @@ extension ACarouselViewModel { var offsetAnimation: Animation? { guard isWrap else { - return .spring() + return _animation?() ?? .spring() } - return isAnimatedOffset ? .spring() : .none + return isAnimatedOffset ? (_animation?() ?? .spring()) : .none } var itemWidth: CGFloat {